aboutsummaryrefslogtreecommitdiff
path: root/sys/imio/iki/stf
diff options
context:
space:
mode:
authorJoseph Hunkeler <jhunkeler@gmail.com>2015-07-08 20:46:52 -0400
committerJoseph Hunkeler <jhunkeler@gmail.com>2015-07-08 20:46:52 -0400
commitfa080de7afc95aa1c19a6e6fc0e0708ced2eadc4 (patch)
treebdda434976bc09c864f2e4fa6f16ba1952b1e555 /sys/imio/iki/stf
downloadiraf-linux-fa080de7afc95aa1c19a6e6fc0e0708ced2eadc4.tar.gz
Initial commit
Diffstat (limited to 'sys/imio/iki/stf')
-rw-r--r--sys/imio/iki/stf/README300
-rw-r--r--sys/imio/iki/stf/mkpkg36
-rw-r--r--sys/imio/iki/stf/stf.h77
-rw-r--r--sys/imio/iki/stf/stfaccess.x58
-rw-r--r--sys/imio/iki/stf/stfaddpar.x94
-rw-r--r--sys/imio/iki/stf/stfclose.x32
-rw-r--r--sys/imio/iki/stf/stfcopy.x43
-rw-r--r--sys/imio/iki/stf/stfcopyf.x92
-rw-r--r--sys/imio/iki/stf/stfctype.x85
-rw-r--r--sys/imio/iki/stf/stfdelete.x40
-rw-r--r--sys/imio/iki/stf/stfget.x97
-rw-r--r--sys/imio/iki/stf/stfhextn.x39
-rw-r--r--sys/imio/iki/stf/stfiwcs.x60
-rw-r--r--sys/imio/iki/stf/stfmerge.x105
-rw-r--r--sys/imio/iki/stf/stfmkpfn.x28
-rw-r--r--sys/imio/iki/stf/stfnewim.x146
-rw-r--r--sys/imio/iki/stf/stfopen.x225
-rw-r--r--sys/imio/iki/stf/stfopix.x202
-rw-r--r--sys/imio/iki/stf/stfordgpb.x64
-rw-r--r--sys/imio/iki/stf/stfrdhdr.x186
-rw-r--r--sys/imio/iki/stf/stfreblk.x65
-rw-r--r--sys/imio/iki/stf/stfrename.x49
-rw-r--r--sys/imio/iki/stf/stfrfits.x266
-rw-r--r--sys/imio/iki/stf/stfrgpb.x179
-rw-r--r--sys/imio/iki/stf/stfupdhdr.x60
-rw-r--r--sys/imio/iki/stf/stfwfits.x147
-rw-r--r--sys/imio/iki/stf/stfwgpb.x174
27 files changed, 2949 insertions, 0 deletions
diff --git a/sys/imio/iki/stf/README b/sys/imio/iki/stf/README
new file mode 100644
index 00000000..5540110b
--- /dev/null
+++ b/sys/imio/iki/stf/README
@@ -0,0 +1,300 @@
+IKI/STF -- IKI kernel for the STScI SDAS/GEIS image format. This format stores
+images in a format which resembles FITS group format. A GROUP FORMAT IMAGE is
+a set of one or more images, all of which are the same size, dimension, and
+datatype, and which share a common FITS header. The individual images in a
+group each has a binary GROUP PARAMETER BLOCK (GPB). The image and associated
+group parameter block are commonly referred to as a GROUP. A group format
+image consists of two files, the FITS format header file for the group,
+and the pixel file containing the image data and GPBs.
+
+
+1. Typical STF group format FITS image header (imname.hhh)
+
+ SIMPLE = F / Standard STF keywords
+ BITPIX = 32
+ DATATYPE= 'REAL*4 '
+ NAXIS = 2
+ NAXIS1 = 512
+ NAXIS2 = 512
+ GROUPS = T
+ PSIZE = 512
+ GCOUNT = 1
+ PCOUNT = 12
+
+ PTYPE1 = 'DATAMIN ' / Define binary group params
+ PSIZE1 = 32
+ PDTYPE1 = 'REAL*4 '
+ (etc, for a total of 3*PCOUNT entries)
+
+ (special keywords and HISTORY cards)
+
+
+2. Pixel file format (imname.hhd) (byte stream, no alignment, no header)
+
+ [1].pixels
+ [1].group parameter block
+ [2].pixels
+ [2].group parameter block
+ ...
+ [GCOUNT].pixels
+ [GCOUNT].group parameter block
+
+
+The chief problems with this format are that the FITS format header can contain
+only parameters which pertain to the group as a whole, while the format of the
+GPBs is fixed at image creation time. Images may be neither deleted from nor
+added to a group. It is possible for parameters in the FITS header to have
+the same names as parameters in the GPBs. Multiple entries for the same
+keyword may appear in the FITS header and the format does not define how
+these are to be handled. Although the format is general enough to support
+any datatype pixels, in practice only REAL*4 can be used as the SDAS software
+maps the pixfile directly into virtual memory.
+
+CAVEAT -- This is an awkward interface and some liberties have been taken in
+the code (hidden, subtle semantics, etc.). At least we were able to confine
+the bad code to this one directory; any problems can be fixed without any
+changes to the rest of IMIO. All of this low level code is expected to be
+thrown out when IMIO is cut over onto DBIO (the upcoming IRAF database
+interface).
+
+
+IKI/STF Pseudocode
+----------------------------
+
+1. Data structures:
+
+ 1.1 IMIO image descriptor
+ header, pixel file descriptors
+ pointer to additional kernel descriptor, if any
+ index of IKI kernel in use
+ pathnames of header, pixel files
+ IM_NDIM, IM_LEN, etc., physical image parameters
+
+ 1.2 STF image descriptor
+ Pointed to by IM_KDES field of IMIO descriptor.
+ Contains values of all reserved fields of STF image header,
+ some of which duplicate values in IMIO descriptor.
+ Group, gcount, size of a group in pixfile, description of
+ the group parameter block, i.e., for each parameter,
+ the offset, datatype type, name, length if array, etc.
+
+ 1.3 IMIO user area (FITS cards)
+ While an image is open, the first few cards in the user area
+ contain the FITS encoded group parameters.
+ The remainder of the user area contains an exact image of
+ all non-reserved keyword cards found in the STF image
+ header (or in the header of some other type of image
+ when making a new_copy of an image stored in some other
+ format).
+
+
+2. Major Procedures
+
+procedure open_image
+
+begin
+ if (mode is not new_image or new_copy) {
+ open_existing_image
+ return
+ }
+
+ We are opening a new_image or new_copy image. The problem here is
+ that the new image might be a group within an existing group format
+ image. This ambiguity is resolved by a simple test on the group
+ index, rather than by a context dependent test on the existence of
+ the group format image. If the mode is new_whatever and the group
+ is 1, a new group format image is created, else if the group is > 1,
+ the indicated group is initialized in an existing group format image.
+
+ if (group > 1) {
+ We are opening a new group within an existing group format image.
+
+ Call open_existing_image to open the group without reading the
+ group parameter block, which has not yet been initialized.
+
+ if (mode is new_image)
+ initialize GPB to pixel coords
+ else if (mode is new_copy)
+ copy old GPB to new image; transform coords if necessary
+
+ Note that when opening a new copy of an existing image as a new
+ group within a group format image, it is not clear what to do
+ with the FITS header of the old image. Our solution is to ignore
+ it, and retain only the GPB, the only part of the old header
+ pertaining directly to the group being accessed.
+
+ } else if (opening group 1 of a new image) {
+ We are creating a new group format image.
+
+ if (mode is new_image)
+ open_new_image
+ else
+ open_new_copy
+ }
+end
+
+
+procedure open_existing_image
+
+begin
+ Allocate STF descriptor, save pointer in imio descriptor.
+ Open image header.
+
+ Read header:
+ process reserved cards into STF descriptor
+ spool other cards
+
+ Load group data block from pixfile, get datamin/datamax:
+ if (there is a gdb) {
+ open pixfile
+ read gdb into buffer
+ for (each param in gdb) {
+ set up parameter descriptor
+ format FITS card and put in imio user area
+ }
+ }
+
+ fetch datamin, datamax from user area
+
+ Set IM_MIN, IM_MAX, IM_LIMTIME from DATAMIN, DATAMAX.
+ Mark end of user area.
+ Copy spooled cards to user area.
+ (increase size of user area if necessary)
+
+ Call imioff to set up imio pixel offset parameters
+end
+
+
+procedure open_new_image
+
+begin
+ Upon entry, the imio iminie procedure has already been called to
+ initialize the imio descriptor for the new image.
+
+ Allocate STF descriptor, save pointer in imio descriptor.
+ Create header file from template dev$pix.hhh.
+ Open new image header.
+
+ (At this point the IMIO header fields IM_NDIM, IM_LEN, etc., and
+ (the STF descriptor fields have not yet been set, and cannot be set
+ (until the image dimensions have been defined by the high level code.
+ (imopix() will later have to fix up the remaining header fields and
+ (set up the default group data block.
+end
+
+
+procedure open_new_copy
+
+begin
+ Upon entry, the imio immaky procedure has already been called to
+ copy the old header to the new and initialize the data
+ dependent fields. This will include the FITS encoded group
+ parameters in the user area of the old image.
+
+ Allocate STF descriptor, save pointer in imio descriptor.
+ Create header file from template dev$pix.hhh.
+ Open new image header.
+
+ Copy the STF descriptor of the old image to the new. Preserve
+ the parameter marking the end of the GPB area of the old
+ user area, as we do not want to write these cards when the
+ header is updated.
+
+ (At this point all header information is set up, except that there
+ (is no pixel file and the pixfile offsets have not been set.
+ (Provided the image dimensions do not change, one could simply
+ (set the pixfile name, call imioff, and do i/o to the image.
+end
+
+
+procedure open_pixel_file
+
+begin
+ (We are called when the first i/o is done to an image. When writing
+ (to a new image, the user may change any of the image header attributes
+ (after the open and before we are called.
+
+ if (pixel file already open)
+ return
+ else if (opening existing image) {
+ open pixel file
+ return
+ }
+
+ if (opening a new image) {
+ Given the values of IM_NDIM and IM_LEN set by the user, set up the
+ STF descriptor including the default group parameter block. Add
+ the FITS encoded cards for the GPB to the image header. Mark the
+ end of the GPB cards, i.e., the start of the real user parameter
+ area. Ignore IM_PIXTYPE; always open an image of type real since
+ that is what the SDAS software requires. Set up the WCS to linear
+ pixel coordinates.
+
+ } else if (opening a new_copy image) {
+ (The STF descriptor and GPB will already have been set up as a
+ (copy of the data structures used by the old image. However,
+ (the user may have changed the values of IM_NDIM and IM_LEN
+ (since the image was opened, and the value of GCOUNT set when
+ (the image was opened may be different than that of the old image.
+
+ Transform the coordinate system of the old image to produce the
+ WCS for the new image, i.e., if an image section was used to
+ reference the old image.
+
+ Make a new STF descriptor using the values of IM_NDIM and IM_LEN
+ given, as for a new_image, but using the WCS information for the
+ new image. The FITS encoded fields in the IMIO user area will be
+ automatically updated by the IMADD functions, or new cards added
+ if not present.
+
+ Merge any additional fields from the old STF descriptor into the
+ new one, e.g., any instrument dependent parameters stored in the
+ GPB.
+
+ (The STF and FITS encoded user area should now contain a full
+ (description of the GPB for the new image.
+ }
+
+ Allocate the pixel file, using the GCOUNT parameter set in the
+ STF descriptor at stf_open time.
+ Open the pixel file.
+
+ Set IM_MIN and IM_MAX to zero (not defined).
+ Call IMIOFF to initialize the pixel offsets.
+end
+
+
+procedure update_image_header
+
+begin
+ Update the values of DATAMIN, DATAMAX from the IMIO header fields.
+
+ Update the binary GPB in the pixel file from the FITS encoded GPB
+ in the IMIO user area, using the GPB structure defined in the
+ STF descriptor.
+
+ Update the STF image header file:
+ Open a new, empty header file using FMKCOPY and OPEN.
+ Format and output FITS cards for the reserved header fields,
+ e.g., SIMPLE, BITPIX, GCOUNT, the GPB information, etc.
+ Copy the user area to the new header file, excluding the
+ GPB cards at the beginning of the user area.
+ Close the new header file and replace the old header file
+ with the new one via a rename operation.
+end
+
+
+procedure close_image
+
+begin
+ (We assume that IMIO has already update the image header if such
+ (is necessary.
+
+ if (pixel file open)
+ close pixel file
+ if (header file open)
+ close header file
+
+ deallocate STF descriptor
+ (IMIO will deallocate the IMIO descriptor)
+end
diff --git a/sys/imio/iki/stf/mkpkg b/sys/imio/iki/stf/mkpkg
new file mode 100644
index 00000000..b28ace96
--- /dev/null
+++ b/sys/imio/iki/stf/mkpkg
@@ -0,0 +1,36 @@
+# Make the IKI/STF interface (STScI SDAS/GEIS group format images)
+
+$checkout libex.a lib$
+$update libex.a
+$checkin libex.a lib$
+$exit
+
+libex.a:
+ #$set XFLAGS = "$(XFLAGS) -qfx"
+ #$set XFLAGS = "$(XFLAGS) -/pg"
+
+ stfaccess.x stf.h
+ stfaddpar.x <imhdr.h> <imio.h> <mach.h> stf.h
+ stfclose.x stf.h <imhdr.h> <imio.h>
+ stfcopy.x stf.h <error.h>
+ stfcopyf.x stf.h
+ stfctype.x stf.h <ctype.h>
+ stfdelete.x stf.h <error.h> <imhdr.h>
+ stfget.x stf.h <ctype.h>
+ stfhextn.x stf.h <imhdr.h> <imio.h>
+ stfiwcs.x stf.h <imhdr.h>
+ stfmerge.x stf.h <imhdr.h> <imio.h> <mach.h>
+ stfmkpfn.x stf.h
+ stfnewim.x stf.h <imhdr.h> <imio.h> <mach.h>
+ stfopen.x stf.h <error.h> <imhdr.h> <imio.h>
+ stfopix.x stf.h <fset.h> <imhdr.h> <imio.h> <mach.h>
+ stfordgpb.x stf.h <mach.h>
+ stfrdhdr.x stf.h <finfo.h> <imhdr.h> <imio.h> <mach.h>
+ stfreblk.x stf.h <imhdr.h> <imio.h>
+ stfrename.x stf.h <error.h>
+ stfrfits.x stf.h <ctype.h> <finfo.h> <fset.h> <imhdr.h> <imio.h>
+ stfrgpb.x stf.h <imhdr.h> <imio.h> <mach.h>
+ stfupdhdr.x stf.h <imhdr.h> <imio.h>
+ stfwfits.x stf.h <error.h> <fio.h> <imhdr.h> <imio.h>
+ stfwgpb.x stf.h <error.h> <imhdr.h> <imio.h> <mach.h>
+ ;
diff --git a/sys/imio/iki/stf/stf.h b/sys/imio/iki/stf/stf.h
new file mode 100644
index 00000000..bf99a07c
--- /dev/null
+++ b/sys/imio/iki/stf/stf.h
@@ -0,0 +1,77 @@
+# STF.H -- IKI/STF internal definitions.
+
+define HDR_TEMPLATE "dev$pix.hhh" # used by fmkcopy to create new header
+define MAX_LENEXTN 3 # max length imagefile extension
+define STF_HDRPATTERN "^??h" # class of legal header extensions
+define STF_DEFHDREXTN "hhh" # default header file extension
+define STF_DEFPIXEXTN "hhd" # default pixel file extension
+define ENV_DEFIMTYPE "imtype" # name of environment variable
+define STF_MAXDIM 7 # max NAXIS
+define MAX_CACHE 5 # max cached header files
+define DEF_CACHE 3 # default size of header file cache
+define ENV_STFCACHE "stfcache" # environment variable for cache size
+define MAX_PCOUNT 99 # max param descriptors
+define SZ_DATATYPE 16 # e.g., `REAL*4'
+define SZ_KEYWORD 8 # size of a FITS keyword
+define SZ_PTYPE 8 # e.g., `CRPIX1'
+define SZ_PDTYPE 16 # e.g., `CHAR*8'
+define SZ_COMMENT FITS_SZCOMMENT # comment string for GPB card
+define SZ_EXTRASPACE (81*32) # extra space for new cards in header
+
+define FITS_RECLEN 80 # length of a FITS record (card)
+define FITS_STARTVALUE 10 # first column of value field
+define FITS_ENDVALUE 30 # last column of value field
+define FITS_SZVALSTR 21 # nchars in value string
+define FITS_SZCOMMENT 50 # max chars in comment, incl. /
+
+# STF image descriptor, used internally by the STF interface. The required
+# header parameters are maintained in this descriptor, everything else is
+# simply copied into the user area of the IMIO descriptor.
+
+define LEN_STFDES (LEN_STFBASE+MAX_PCOUNT*LEN_PDES)
+define STF_CACHE STF_BITPIX # cache descriptor starting here
+define STF_CACHELEN (33+STF_PCOUNT($1)*LEN_PDES)
+define LEN_STFBASE 43
+
+define STF_ACMODE Memi[$1] # image access mode
+define STF_NEWIMAGE Memi[$1+1] # creating entire new STF format image?
+define STF_GROUP Memi[$1+2] # group to be accessed
+define STF_SZGROUP Memi[$1+3] # size of image+hdr in pixfile, chars
+define STF_PFD Memi[$1+4] # pixfile file descriptor
+define STF_GRARG Memi[$1+5] # group index given in image name
+ # (extra space)
+define STF_BITPIX Memi[$1+10] # bits per pixel
+define STF_NAXIS Memi[$1+11] # number of axes in image
+define STF_GROUPS Memi[$1+12] # group format?
+define STF_GCOUNT Memi[$1+13] # number of groups in STF image
+define STF_PSIZE Memi[$1+14] # size of GPB, bits
+define STF_PCOUNT Memi[$1+15] # number of parameters in GPB
+define STF_DATATYPE Memc[P2C($1+16)]# datatype string
+define STF_LENAXIS Memi[$1+35+$2-1]# 35:41 = [7] max
+define STF_PDES (($1)+43+((($2)-1)*LEN_PDES))
+
+# GPB Parameter descriptor.
+define LEN_PDES 81
+define P_OFFSET Memi[$1] # struct offset of parameter
+define P_SPPTYPE Memi[$1+1] # SPP datatype of parameter
+define P_LEN Memi[$1+2] # number of elements
+define P_PSIZE Memi[$1+3] # field size, bits
+define P_PTYPEP (P2C($1+4)) # pointer to parameter name
+define P_PTYPE Memc[P2C($1+4)] # parameter name
+define P_PDTYPE Memc[P2C($1+13)]# datatype string
+define P_COMMENT Memc[P2C($1+30)]# comment string
+
+# Reserved FITS keywords known to this code.
+define KW_BITPIX 1
+define KW_DATATYPE 2
+define KW_END 3
+define KW_GCOUNT 4
+define KW_GROUPS 5
+define KW_NAXIS 6
+define KW_NAXISN 7
+define KW_PCOUNT 8
+define KW_PDTYPE 9
+define KW_PSIZE 10
+define KW_PSIZEN 11
+define KW_PTYPE 12
+define KW_SIMPLE 13
diff --git a/sys/imio/iki/stf/stfaccess.x b/sys/imio/iki/stf/stfaccess.x
new file mode 100644
index 00000000..40907c69
--- /dev/null
+++ b/sys/imio/iki/stf/stfaccess.x
@@ -0,0 +1,58 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include "stf.h"
+
+# STF_ACCESS -- Test the accessibility or existence of an existing image, or
+# the legality of the name of a new image.
+
+procedure stf_access (kernel, root, extn, acmode, status)
+
+int kernel #I IKI kernel
+char root[ARB] #I root filename
+char extn[ARB] #I extension (SET on output if none specified)
+int acmode #I access mode (0 to test only existence)
+int status #O return value
+
+int i
+pointer sp, fname, kextn
+int access(), iki_validextn(), iki_getextn(), btoi()
+
+begin
+ call smark (sp)
+ call salloc (fname, SZ_PATHNAME, TY_CHAR)
+ call salloc (kextn, MAX_LENEXTN, TY_CHAR)
+
+ # If new image, test only the legality of the given extension.
+ # This is used to select a kernel given the imagefile extension.
+
+ if (acmode == NEW_IMAGE || acmode == NEW_COPY) {
+ status = btoi (iki_validextn (kernel, extn) > 0)
+ call sfree (sp)
+ return
+ }
+
+ status = NO
+
+ # If no extension was given, look for a file with the default
+ # extension, and return the actual extension if an image with the
+ # default extension is found.
+
+ if (extn[1] == EOS) {
+ do i = 1, ARB {
+ if (iki_getextn (kernel, i, Memc[kextn], MAX_LENEXTN) <= 0)
+ break
+ call iki_mkfname (root, Memc[kextn], Memc[fname], SZ_PATHNAME)
+ if (access (Memc[fname], acmode, 0) == YES) {
+ call strcpy (Memc[kextn], extn, MAX_LENEXTN)
+ status = YES
+ break
+ }
+ }
+ } else if (iki_validextn (kernel, extn) == kernel) {
+ call iki_mkfname (root, extn, Memc[fname], SZ_PATHNAME)
+ if (access (Memc[fname], acmode, 0) == YES)
+ status = YES
+ }
+
+ call sfree (sp)
+end
diff --git a/sys/imio/iki/stf/stfaddpar.x b/sys/imio/iki/stf/stfaddpar.x
new file mode 100644
index 00000000..65a90f80
--- /dev/null
+++ b/sys/imio/iki/stf/stfaddpar.x
@@ -0,0 +1,94 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <imhdr.h>
+include <imio.h>
+include <mach.h>
+include "stf.h"
+
+# STF_ADDPAR -- Encode a parameter in FITS format and add it to the FITS format
+# IMIO user area; initialize the entry for the parameter in the GPB descriptor
+# as well.
+
+procedure stf_addpar (im, pname, dtype, plen, pval, pno)
+
+pointer im #I image descriptor
+char pname[ARB] #I parameter name
+int dtype #I SPP datatype of parameter
+int plen #I length (> 1 if array)
+char pval[ARB] #I string encoded initial parameter value
+int pno #U parameter number
+
+bool bval
+real rval
+double dval
+short sval
+long lval
+pointer pp, stf
+
+bool initparam
+int ival, ip, junk
+int ctoi(), ctor(), ctod(), imaccf()
+errchk imadds, imaddl, imaddr, imaddd, imastr
+
+begin
+ stf = IM_KDES(im)
+ pp = STF_PDES(stf,pno)
+ ip = 1
+
+ call strcpy (pname, P_PTYPE(pp), SZ_PTYPE)
+
+ # Initialize the parameter only if not already defined in header.
+ initparam = (imaccf (im, pname) == NO)
+
+ switch (dtype) {
+ case TY_BOOL:
+ call strcpy ("LOGICAL*4", P_PDTYPE(pp), SZ_PDTYPE)
+ P_PSIZE(pp) = plen * SZ_BOOL * SZB_CHAR * NBITS_BYTE
+ if (initparam) {
+ bval = (pval[1] == 'T')
+ call imaddb (im, P_PTYPE(pp), bval)
+ }
+ case TY_SHORT:
+ call strcpy ("INTEGER*2", P_PDTYPE(pp), SZ_PDTYPE)
+ P_PSIZE(pp) = plen * SZ_SHORT * SZB_CHAR * NBITS_BYTE
+ if (initparam) {
+ junk = ctoi (pval, ip, ival)
+ sval = ival
+ call imadds (im, P_PTYPE(pp), sval)
+ }
+ case TY_LONG:
+ call strcpy ("INTEGER*4", P_PDTYPE(pp), SZ_PDTYPE)
+ P_PSIZE(pp) = plen * SZ_LONG * SZB_CHAR * NBITS_BYTE
+ if (initparam) {
+ junk = ctoi (pval, ip, ival)
+ lval = ival
+ call imaddl (im, P_PTYPE(pp), lval)
+ }
+ case TY_REAL:
+ call strcpy ("REAL*4", P_PDTYPE(pp), SZ_PDTYPE)
+ P_PSIZE(pp) = plen * SZ_REAL * SZB_CHAR * NBITS_BYTE
+ if (initparam) {
+ junk = ctor (pval, ip, rval)
+ call imaddr (im, P_PTYPE(pp), rval)
+ }
+ case TY_DOUBLE:
+ call strcpy ("REAL*8", P_PDTYPE(pp), SZ_PDTYPE)
+ P_PSIZE(pp) = plen * SZ_DOUBLE * SZB_CHAR * NBITS_BYTE
+ if (initparam) {
+ junk = ctod (pval, ip, dval)
+ call imaddd (im, P_PTYPE(pp), dval)
+ }
+ default:
+ call sprintf (P_PDTYPE(pp), SZ_PDTYPE, "CHARACTER*%d")
+ call pargi (plen)
+ P_PSIZE(pp) = plen * NBITS_BYTE
+ if (initparam)
+ call imastr (im, P_PTYPE(pp), pval)
+ }
+
+ P_OFFSET(pp) = 0
+ P_SPPTYPE(pp) = dtype
+ P_LEN(pp) = plen
+
+ pno = pno + 1
+end
diff --git a/sys/imio/iki/stf/stfclose.x b/sys/imio/iki/stf/stfclose.x
new file mode 100644
index 00000000..89981578
--- /dev/null
+++ b/sys/imio/iki/stf/stfclose.x
@@ -0,0 +1,32 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <imhdr.h>
+include <imio.h>
+include "stf.h"
+
+# STF_CLOSE -- Close an STF format image. There is little for us to do, since
+# IMIO will already have updated the header if necessary and flushed any pixel
+# output. Neither do we have to deallocate the IMIO descriptor, since it was
+# allocated by IMIO.
+
+procedure stf_close (im, status)
+
+pointer im # image descriptor
+int status
+
+pointer stf
+errchk close
+
+begin
+ stf = IM_KDES(im)
+
+ # Close the pixel file and header file, if open.
+ if (STF_PFD(stf) != NULL)
+ call close (STF_PFD(stf))
+ if (IM_HFD(im) != NULL)
+ call close (IM_HFD(im))
+
+ # Deallocate the STF descirptor.
+ call mfree (IM_KDES(im), TY_STRUCT)
+ status = OK
+end
diff --git a/sys/imio/iki/stf/stfcopy.x b/sys/imio/iki/stf/stfcopy.x
new file mode 100644
index 00000000..e8643600
--- /dev/null
+++ b/sys/imio/iki/stf/stfcopy.x
@@ -0,0 +1,43 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <error.h>
+include "stf.h"
+
+# STF_COPY -- Copy an image. A special operator is provided for fast, blind
+# copies of entire images.
+
+procedure stf_copy (kernel, oroot, oextn, nroot, nextn, status)
+
+int kernel #I IKI kernel
+char oroot[ARB] # old image root name
+char oextn[ARB] # old image extn
+char nroot[ARB] # new image root name
+char nextn[ARB] # old image extn
+int status
+
+pointer sp
+pointer ohdr_fname, opix_fname, nhdr_fname, npix_fname
+
+begin
+ call smark (sp)
+ call salloc (ohdr_fname, SZ_PATHNAME, TY_CHAR)
+ call salloc (opix_fname, SZ_PATHNAME, TY_CHAR)
+ call salloc (nhdr_fname, SZ_PATHNAME, TY_CHAR)
+ call salloc (npix_fname, SZ_PATHNAME, TY_CHAR)
+
+ # Generate filenames.
+ call iki_mkfname (oroot, oextn, Memc[ohdr_fname], SZ_PATHNAME)
+ call iki_mkfname (nroot, nextn, Memc[nhdr_fname], SZ_PATHNAME)
+
+ call stf_mkpixfname (oroot, oextn, Memc[opix_fname], SZ_PATHNAME)
+ call stf_mkpixfname (nroot, nextn, Memc[npix_fname], SZ_PATHNAME)
+
+ # If the header cannot be copied, leave the pixfile alone.
+ iferr (call fcopy (Memc[ohdr_fname], Memc[nhdr_fname]))
+ call erract (EA_WARN)
+ else iferr (call fcopy (Memc[opix_fname], Memc[npix_fname]))
+ call erract (EA_WARN)
+
+ call sfree (sp)
+ status = OK
+end
diff --git a/sys/imio/iki/stf/stfcopyf.x b/sys/imio/iki/stf/stfcopyf.x
new file mode 100644
index 00000000..7402c879
--- /dev/null
+++ b/sys/imio/iki/stf/stfcopyf.x
@@ -0,0 +1,92 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include "stf.h"
+
+define NKW 4 # number of reserved header keywords
+
+
+# STF_COPYFITS -- Copy the spooled FITS header, separating out the GPB cards
+# and returning either or both types of cards on the two output streams.
+
+procedure stf_copyfits (stf, spool, gpb, user)
+
+pointer stf #I pointer to STF descriptor
+int spool #I spooled header to read
+int gpb #I stream to receive GPB cards, or NULL
+int user #I stream to receive user cards, or NULL
+
+bool keyword
+int p_ch[MAX_PCOUNT+NKW]
+pointer p_len[MAX_PCOUNT+NKW]
+pointer p_namep[MAX_PCOUNT+NKW]
+int delim, ch, npars, ngpbpars, i
+pointer sp, lbuf, sbuf, pp, op, kw[NKW]
+int strncmp(), getline(), strlen(), gstrcpy()
+errchk getline, putline
+
+begin
+ call smark (sp)
+ call salloc (lbuf, SZ_LINE, TY_CHAR)
+ call salloc (sbuf, SZ_LINE, TY_CHAR)
+
+ # The following reserved keywords describing the GPB are added to
+ # the user area by stf_rdheader, and must be filtered out along with
+ # the group parameters. Since the number of reserved or group
+ # parameters is normally small (only a dozen or so typically) a
+ # simple 1 character - 2 thread hashing scheme is probably faster,
+ # and certainly simpler, than a full hash table keyword lookup.
+
+ op = sbuf
+ npars = NKW
+ kw[1] = op; op = op + gstrcpy ("GROUPS", Memc[op], ARB) + 1
+ kw[2] = op; op = op + gstrcpy ("GCOUNT", Memc[op], ARB) + 1
+ kw[3] = op; op = op + gstrcpy ("PCOUNT", Memc[op], ARB) + 1
+ kw[4] = op; op = op + gstrcpy ("PSIZE", Memc[op], ARB) + 1
+
+ do i = 1, npars {
+ p_namep[i] = kw[i]
+ p_len[i] = strlen(Memc[kw[i]])
+ p_ch[i] = Memc[kw[i]+2]
+ }
+
+ # Add the GPB parameters to the list of group related parameters.
+ ngpbpars = min (MAX_PCOUNT, STF_PCOUNT(stf))
+ do i = 1, ngpbpars {
+ npars = npars + 1
+ pp = STF_PDES(stf,i)
+ p_namep[npars] = P_PTYPEP(pp)
+ p_len[npars] = strlen(P_PTYPE(pp))
+ p_ch[npars] = Memc[p_namep[npars]+2]
+ }
+
+ # Determine the type of each card and copy it to the appropriate
+ # output stream.
+
+ while (getline (spool, Memc[lbuf]) != EOF) {
+ # Does this user card redefine a reserved keyword?
+ keyword = false
+ ch = Memc[lbuf+2]
+ do i = 1, npars {
+ if (ch != p_ch[i])
+ next
+ delim = Memc[lbuf+p_len[i]]
+ if (delim != ' ' && delim != '=')
+ next
+ if (strncmp (Memc[lbuf], Memc[p_namep[i]], p_len[i]) == 0) {
+ keyword = true
+ break
+ }
+ }
+
+ # Copy the card to the appropriate stream.
+ if (keyword) {
+ if (gpb != NULL)
+ call putline (gpb, Memc[lbuf])
+ } else {
+ if (user != NULL)
+ call putline (user, Memc[lbuf])
+ }
+ }
+
+ call sfree (sp)
+end
diff --git a/sys/imio/iki/stf/stfctype.x b/sys/imio/iki/stf/stfctype.x
new file mode 100644
index 00000000..9c48f65a
--- /dev/null
+++ b/sys/imio/iki/stf/stfctype.x
@@ -0,0 +1,85 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <ctype.h>
+include "stf.h"
+
+# STF_CTYPE -- Determine the type of a FITS card. STF recognizes only those
+# cards which define the image format and the group parameter block.
+
+int procedure stf_ctype (card, index)
+
+char card[ARB] #I FITS card (or keyword)
+int index #O index number, if any
+
+int ch1, ch2, ip
+int strncmp(), ctoi()
+
+begin
+ ch1 = card[1]
+ ch2 = card[2]
+
+ # The set of keywords is fixed and small, so a simple brute force
+ # recognizer is about as good as anything.
+
+ if (ch1 == 'B') {
+ if (ch2 == 'I')
+ if (strncmp (card, "BITPIX ", 8) == 0)
+ return (KW_BITPIX) # BITPIX
+ } else if (ch1 == 'D') {
+ if (ch2 == 'A')
+ if (strncmp (card, "DATATYPE", 8) == 0)
+ return (KW_DATATYPE) # DATATYPE
+ } else if (ch1 == 'E') {
+ if (ch2 == 'N')
+ if (card[3] == 'D' && card[4] == ' ')
+ return (KW_END) # END card
+ } else if (ch1 == 'G') {
+ if (ch2 == 'C') {
+ if (strncmp (card, "GCOUNT ", 8) == 0)
+ return (KW_GCOUNT) # GCOUNT
+ } else if (ch2 == 'R') {
+ if (strncmp (card, "GROUPS ", 8) == 0)
+ return (KW_GROUPS) # GROUPS
+ }
+ } else if (ch1 == 'N') {
+ if (ch2 == 'A')
+ if (strncmp (card, "NAXIS", 5) == 0)
+ if (card[6] == ' ')
+ return (KW_NAXIS) # NAXIS
+ else if (IS_DIGIT(card[6])) {
+ index = TO_INTEG(card[6])
+ return (KW_NAXISN) # NAXISn
+ }
+ } else if (ch1 == 'P') {
+ if (ch2 == 'C') {
+ if (strncmp (card, "PCOUNT ", 8) == 0)
+ return (KW_PCOUNT) # PCOUNT
+ } else if (ch2 == 'D') {
+ if (strncmp (card, "PDTYPE", 6) == 0) {
+ ip = 7
+ if (ctoi (card, ip, index) > 0)
+ return (KW_PDTYPE) # PDTYPEn
+ }
+ } else if (ch2 == 'S') {
+ if (strncmp (card, "PSIZE", 5) == 0) {
+ ip = 6
+ if (card[ip] == ' ')
+ return (KW_PSIZE)
+ else if (ctoi (card, ip, index) > 0)
+ return (KW_PSIZEN) # PSIZEn
+ }
+ } else if (ch2 == 'T') {
+ if (strncmp (card, "PTYPE", 5) == 0) {
+ ip = 6
+ if (ctoi (card, ip, index) > 0)
+ return (KW_PTYPE) # PTYPEn
+ }
+ }
+ } else if (ch1 == 'S') {
+ if (ch2 == 'I')
+ if (strncmp (card, "SIMPLE ", 8) == 0)
+ return (KW_SIMPLE) # SIMPLE
+ }
+
+ return (ERR)
+end
diff --git a/sys/imio/iki/stf/stfdelete.x b/sys/imio/iki/stf/stfdelete.x
new file mode 100644
index 00000000..dd319f12
--- /dev/null
+++ b/sys/imio/iki/stf/stfdelete.x
@@ -0,0 +1,40 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <error.h>
+include <imhdr.h>
+include "stf.h"
+
+# STF_DELETE -- Delete an image. A special operator is required since the
+# image is stored as two files.
+
+procedure stf_delete (kernel, root, extn, status)
+
+int kernel #I IKI kernel
+char root[ARB] #I root filename
+char extn[ARB] #U header file extension
+int status #O return value
+
+pointer sp
+pointer hdr_fname, pix_fname
+int access()
+
+begin
+ call smark (sp)
+ call salloc (hdr_fname, SZ_PATHNAME, TY_CHAR)
+ call salloc (pix_fname, SZ_PATHNAME, TY_CHAR)
+
+ # Generate filename.
+ call iki_mkfname (root, extn, Memc[hdr_fname], SZ_PATHNAME)
+ call stf_mkpixfname (root, extn, Memc[pix_fname], SZ_PATHNAME)
+
+ # If the header cannot be deleted, leave the pixfile alone.
+ iferr (call delete (Memc[hdr_fname]))
+ call erract (EA_WARN)
+ else if (access (Memc[pix_fname],0,0) == YES) {
+ iferr (call delete (Memc[pix_fname]))
+ call erract (EA_WARN)
+ }
+
+ status = OK
+ call sfree (sp)
+end
diff --git a/sys/imio/iki/stf/stfget.x b/sys/imio/iki/stf/stfget.x
new file mode 100644
index 00000000..bacbc8d7
--- /dev/null
+++ b/sys/imio/iki/stf/stfget.x
@@ -0,0 +1,97 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <ctype.h>
+include "stf.h"
+
+# STF_GETI -- Return the integer value of a FITS encoded card.
+
+procedure stf_geti (card, ival)
+
+char card[ARB] # card to be decoded
+int ival # receives integer value
+
+int ip, ctoi()
+char sval[FITS_SZVALSTR]
+
+begin
+ call stf_gets (card, sval, FITS_SZVALSTR)
+ ip = 1
+ if (ctoi (sval, ip, ival) <= 0)
+ ival = 0
+end
+
+
+# STF_GETB -- Return the boolean/integer value of a FITS encoded card.
+
+procedure stf_getb (card, bval)
+
+char card[ARB] # card to be decoded
+int bval # receives YES/NO
+
+char sval[FITS_SZVALSTR]
+
+begin
+ call stf_gets (card, sval, FITS_SZVALSTR)
+ if (sval[1] == 'T')
+ bval = YES
+ else
+ bval = NO
+end
+
+
+# STF_GETS -- Get the string value of a FITS encoded card. Strip leading
+# and trailing whitespace and any quotes.
+
+procedure stf_gets (card, outstr, maxch)
+
+char card[ARB] # FITS card to be decoded
+char outstr[ARB] # output string to receive parameter value
+int maxch
+
+int ip, op
+int ctowrd(), strlen()
+
+begin
+ ip = FITS_STARTVALUE
+ if (ctowrd (card, ip, outstr, maxch) > 0) {
+ # Strip trailing whitespace.
+ op = strlen (outstr)
+ while (op > 0 && (IS_WHITE(outstr[op]) || outstr[op] == '\n'))
+ op = op - 1
+ outstr[op+1] = EOS
+ } else
+ outstr[1] = EOS
+end
+
+
+# STF_GETCMT -- Get the comment field of a FITS encoded card.
+
+procedure stf_getcmt (card, comment, maxch)
+
+char card[ARB] #I FITS card to be decoded
+char comment[ARB] #O output string to receive comment
+int maxch #I max chars out
+
+int ip, op
+int lastch
+
+begin
+ # Find the slash which marks the beginning of the comment field.
+ ip = FITS_ENDVALUE + 1
+ while (card[ip] != EOS && card[ip] != '\n' && card[ip] != '/')
+ ip = ip + 1
+
+ # Copy the comment to the output string, omitting the /, any
+ # trailing blanks, and the newline.
+
+ lastch = 0
+ do op = 1, maxch {
+ if (card[ip] == EOS)
+ break
+ ip = ip + 1
+ comment[op] = card[ip]
+ if (card[ip] > ' ')
+ lastch = op
+ }
+ comment[lastch+1] = EOS
+end
diff --git a/sys/imio/iki/stf/stfhextn.x b/sys/imio/iki/stf/stfhextn.x
new file mode 100644
index 00000000..45e89f7a
--- /dev/null
+++ b/sys/imio/iki/stf/stfhextn.x
@@ -0,0 +1,39 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <imhdr.h>
+include <imio.h>
+include "stf.h"
+
+
+# STF_GETHDREXTN -- Get the default header file extension.
+
+procedure stf_gethdrextn (im, o_im, acmode, outstr, maxch)
+
+pointer im, o_im #I image descriptors
+int acmode #I access mode
+char outstr[maxch] #O receives header extension
+int maxch #I max chars out
+
+bool inherit
+int kernel, old_kernel
+int fnextn(), iki_getextn(), iki_getpar()
+
+begin
+ # Use the same extension as the input file if this is a new copy
+ # image of the same type as the input and inherit is enabled.
+ # If we have to get the extension using iki_getextn, the default
+ # extension for a new image is the first extension defined (index=1).
+
+ kernel = IM_KERNEL(im)
+
+ old_kernel = 0
+ if (acmode == NEW_COPY && o_im != NULL)
+ old_kernel = IM_KERNEL(o_im)
+
+ inherit = (iki_getpar ("inherit") == YES)
+ if (inherit && acmode == NEW_COPY && kernel == old_kernel) {
+ if (fnextn (IM_HDRFILE(im), outstr, maxch) <= 0)
+ call strcpy (STF_DEFHDREXTN, outstr, maxch)
+ } else if (iki_getextn (kernel, 1, outstr, maxch) < 0)
+ call strcpy (STF_DEFHDREXTN, outstr, maxch)
+end
diff --git a/sys/imio/iki/stf/stfiwcs.x b/sys/imio/iki/stf/stfiwcs.x
new file mode 100644
index 00000000..415b9a76
--- /dev/null
+++ b/sys/imio/iki/stf/stfiwcs.x
@@ -0,0 +1,60 @@
+include <imhdr.h>
+include "stf.h"
+
+# STF_INITWCS -- Check for an unitialized WCS and set up a unitary pixel
+# WCS in this case.
+
+procedure stf_initwcs (im)
+
+pointer im #I image descriptor
+
+real v
+int ndim, i, j
+bool have_wcs, wcsok
+char pname[SZ_KEYWORD]
+bool fp_equalr()
+real imgetr()
+
+begin
+ ndim = IM_NDIM(im)
+ have_wcs = false
+ wcsok = false
+
+ # Scan the header to determine if we have any WCS information (assume
+ # there is a WCS if any CDi_j cards are found) and if it has been
+ # initialized (at least one matrix element is nonzero). Note that
+ # we are checking only to see if the WCS has been initialized, not
+ # if it is a valid WCS.
+
+ do j = 1, ndim {
+ do i = 1, ndim {
+ call sprintf (pname, SZ_KEYWORD, "CD%d_%d")
+ call pargi (i)
+ call pargi (j)
+ ifnoerr (v = imgetr (im, pname)) {
+ have_wcs = true
+ if (!fp_equalr (v, 0.0)) {
+ wcsok = true
+ break
+ }
+ }
+ }
+ if (wcsok)
+ break
+ }
+
+ # If we found some WCS information and the CD matrix is zero, init
+ # the WCS.
+
+ if (have_wcs && !wcsok)
+ do i = 1, ndim {
+ call sprintf (pname, SZ_KEYWORD, "CTYPE%d")
+ call pargi (i)
+ call imastr (im, pname, "PIXEL")
+
+ call sprintf (pname, SZ_KEYWORD, "CD%d_%d")
+ call pargi (i)
+ call pargi (i)
+ call imaddr (im, pname, 1.0)
+ }
+end
diff --git a/sys/imio/iki/stf/stfmerge.x b/sys/imio/iki/stf/stfmerge.x
new file mode 100644
index 00000000..a98ee877
--- /dev/null
+++ b/sys/imio/iki/stf/stfmerge.x
@@ -0,0 +1,105 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <imhdr.h>
+include <imio.h>
+include <mach.h>
+include "stf.h"
+
+# STF_MERGEGPB -- Merge the non-reserved parameters from an existing GPB into
+# a new GPB; called to construct a new GPB when an image is opened in new-copy
+# mode. Since the new copy may not be the same size and dimension as the
+# original, the reserved parameters must be set up fresh for the new copy
+# image, i.e., we cannot simply copy them from the old image. Likewise, the
+# WCS must be transformed if the new copy image does not geometrically overlay
+# the original.
+#
+# NOTE: no longer called by stf_opix; save this code for future use!
+# <dlb--11/4/87>
+
+procedure stf_mergegpb (n_im, o_im)
+
+pointer n_im # new copy image
+pointer o_im # image being copied
+
+bool match
+int n_i, o_i, n, ip, axis
+int up_psize
+pointer sp, cd_pat, n_stf, o_stf, n_pp, o_pp
+int strncmp(), strlen(), patmake(), patmatch(), ctoi()
+
+begin
+ call smark (sp)
+ call salloc (cd_pat, SZ_LINE, TY_CHAR)
+
+ # Make a pattern to match the CDa_b parameter names.
+ if (patmake ("CD[0-9]_[0-9]", Memc[cd_pat], SZ_LINE) < 0)
+ ; # cannot happen
+
+ n_stf = IM_KDES(n_im)
+ o_stf = IM_KDES(o_im)
+
+ # Examine each parameter in the old GPB and make an entry for the new
+ # ones in the new GPB. Note that all we are doing here is defining
+ # the structure; the GPB data is not physically written until the new
+ # header is updated on disk. The FITS encoded values for the GPB
+ # parameters will already have been copied to the user area of the
+ # new image.
+
+ up_psize = 0
+ for (o_i=1; o_i <= STF_PCOUNT(o_stf); o_i=o_i+1) {
+ o_pp = STF_PDES(o_stf,o_i)
+ n = strlen (P_PTYPE(o_pp))
+
+ if (P_PTYPE(o_pp) == 'C')
+ if (strncmp (P_PTYPE(o_pp), "CRPIX", 5) == 0 ||
+ strncmp (P_PTYPE(o_pp), "CRVAL", 5) == 0 ||
+ strncmp (P_PTYPE(o_pp), "CTYPE", 5) == 0 ||
+ patmatch (P_PTYPE(o_pp), Memc[cd_pat]) > 0) {
+
+ ip = 6
+ if (ctoi (P_PTYPE(o_pp), ip, axis) <= 0)
+ axis = IM_MAXDIM + 1
+ if (axis <= STF_NAXIS(n_stf))
+ next
+ }
+
+ # Is there a parameter of the same name in the new descriptor?
+ match = false
+ for (n_i=1; n_i <= STF_PCOUNT(n_stf); n_i=n_i+1) {
+ n_pp = STF_PDES(n_stf,n_i)
+ if (strncmp (P_PTYPE(o_pp), P_PTYPE(n_pp), n) == 0) {
+ match = true
+ break
+ }
+ }
+
+ # If there was no match for the parameter, add a definition for
+ # it to the GPB descriptor for the new image.
+
+ if (!match) {
+ n = STF_PCOUNT(n_stf) + 1
+ if (n > MAX_PCOUNT)
+ call error (4, "stf_merge: too many group parameters")
+
+ STF_PCOUNT(n_stf) = n
+ up_psize = up_psize + P_PSIZE(o_pp)
+ n_pp = STF_PDES(n_stf,n)
+
+ P_SPPTYPE(n_pp) = P_SPPTYPE(o_pp)
+ P_PSIZE(n_pp) = P_PSIZE(o_pp)
+ P_LEN(n_pp) = P_LEN(o_pp)
+
+ call strcpy (P_PTYPE(o_pp), P_PTYPE(n_pp), SZ_PTYPE)
+ call strcpy (P_PDTYPE(o_pp), P_PDTYPE(n_pp), SZ_PDTYPE)
+ }
+ }
+
+ # Moved the PSIZE, SZGROUP calculations here to fix error in the
+ # computation of PSIZE--dlb, 11/2/87
+
+ STF_PSIZE(n_stf) = STF_PSIZE(n_stf) + up_psize
+ STF_SZGROUP(n_stf) = STF_SZGROUP(n_stf) +
+ up_psize / (SZB_CHAR * NBITS_BYTE)
+
+ call sfree (sp)
+end
diff --git a/sys/imio/iki/stf/stfmkpfn.x b/sys/imio/iki/stf/stfmkpfn.x
new file mode 100644
index 00000000..4568efd8
--- /dev/null
+++ b/sys/imio/iki/stf/stfmkpfn.x
@@ -0,0 +1,28 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include "stf.h"
+
+# STF_MKPIXFNAME -- Given the root and extn fields of the image header filename,
+# construct the pixel file name. The pixel file has the same root name as
+# the header and the first two characters of the extension are the same as for
+# the header, if a header extension was given.
+
+procedure stf_mkpixfname (hdr_root, hdr_extn, pixfname, maxch)
+
+char hdr_root[ARB] # root name of header file
+char hdr_extn[ARB] # extension of header file
+char pixfname[maxch] # receives pixel filename
+int maxch
+
+int i
+char pix_extn[MAX_LENEXTN]
+
+begin
+ call strcpy (STF_DEFPIXEXTN, pix_extn, MAX_LENEXTN)
+ if (hdr_extn[1] != EOS) {
+ for (i=1; i < MAX_LENEXTN; i=i+1)
+ pix_extn[i] = hdr_extn[i]
+ }
+
+ call iki_mkfname (hdr_root, pix_extn, pixfname, maxch)
+end
diff --git a/sys/imio/iki/stf/stfnewim.x b/sys/imio/iki/stf/stfnewim.x
new file mode 100644
index 00000000..3e8a95ed
--- /dev/null
+++ b/sys/imio/iki/stf/stfnewim.x
@@ -0,0 +1,146 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <imhdr.h>
+include <imio.h>
+include <mach.h>
+include "stf.h"
+
+define NBITS_CHAR (SZB_CHAR * NBITS_BYTE)
+
+
+# STF_NEWIMAGE -- Set up the IMIO/STF descriptor for an image opened with mode
+# new_image or new_copy of non-STF images. Note that the parameters GROUP
+# and GCOUNT were set earlier by stf_open().
+
+procedure stf_newimage (im)
+
+pointer im # image descriptor
+
+pointer stf
+pointer o_im
+long totpix
+char pname[SZ_KEYWORD]
+int old_kernel, pixtype, bitpix, nbytes, pno, ndim, i, j
+errchk stf_addpar
+string zero "0"
+string one "1"
+
+include <szpixtype.inc>
+
+begin
+ # Get length of axes and datatype from imio descriptor;
+ # these may be changed by the user between image mapping
+ # and first i/o to pixfile so we set up the group parameter block
+ # and size of pixfile on first i/o operation
+
+ stf = IM_KDES(im)
+ o_im = IM_OHDR(im)
+ ndim = IM_NDIM(im)
+ STF_NAXIS(stf) = ndim
+ do i = 1, ndim
+ STF_LENAXIS(stf,i) = IM_LEN(im,i)
+
+ # Get datatype for the pixfile; stf_open has set this to datatype
+ # of template file if it exists, otherwise defaults to real(assuming
+ # the user hasn't changed it by now)
+
+ pixtype = IM_PIXTYPE(im)
+
+ bitpix = pix_size[pixtype] * NBITS_CHAR
+ nbytes = bitpix / NBITS_BYTE
+
+ call sprintf (STF_DATATYPE(stf), SZ_DATATYPE, "%s*%d")
+ switch (pixtype) {
+ case TY_USHORT:
+ call pargstr ("UNSIGNED")
+ case TY_SHORT, TY_LONG, TY_INT:
+ call pargstr ("INTEGER")
+ case TY_REAL, TY_DOUBLE:
+ call pargstr ("REAL")
+ case TY_COMPLEX:
+ call pargstr ("COMPLEX")
+ default:
+ pixtype = TY_REAL
+ bitpix = SZ_REAL * NBITS_CHAR
+ nbytes = bitpix / NBITS_BYTE
+ call pargstr ("REAL")
+ }
+ call pargi (nbytes)
+
+ STF_BITPIX(stf) = bitpix
+
+ # Set the IMIO min/max fields.
+
+ IM_MIN(im) = 0.
+ IM_MAX(im) = 0.
+ IM_LIMTIME(im) = 0
+
+ # For a new copy image(of an already-existing file), DO NOT add group
+ # parameters to the GPB, unless the original image is not an STF
+ # image. The following are the "standard" set of datamin/max and the
+ # FITS coordinate parms which SDAS files are supposed to have.
+
+ if (IM_ACMODE(im) == NEW_COPY && o_im != NULL)
+ old_kernel = IM_KERNEL(o_im)
+
+ if ((IM_ACMODE(im) == NEW_FILE) ||
+ ((IM_ACMODE(im) == NEW_COPY) && IM_KERNEL(im) != old_kernel)) {
+
+ # Set up the standard STF group parameter block parameters.
+ STF_GROUPS(stf) = YES
+ STF_PCOUNT(stf) = 2 + (ndim * 3) + (ndim * ndim)
+ STF_PSIZE(stf) = 2 * (SZ_REAL * NBITS_CHAR) + # DATAMIN/MAX
+ ndim * (SZ_DOUBLE * NBITS_CHAR) + # CRVALn
+ ndim * (SZ_REAL * NBITS_CHAR) + # CRPIXn
+ ndim * (8 * NBITS_BYTE) + # CTYPEn
+ (ndim * ndim) * (SZ_REAL * NBITS_CHAR) # CD matrix
+
+ # 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)
+ IM_KDES(im) = stf
+ }
+
+ # Set up the group data block in the STF descriptor and in
+ # the IMIO FITS format user area. WARNING--the STF kernel
+ # is implicitly assuming that the GPB related parameters
+ # in non-STF format images are at the beginning of the user
+ # area, if they are present at all. If this is not true
+ # then the following code will APPEND them to the user area.
+ # At STScI, non-STF format images are usually made from STF
+ # images and these parameters are at the beginning of the user
+ # area in that case.
+
+ pno = 1
+ call stf_addpar (im, "DATAMIN", TY_REAL, 1, zero, pno)
+ call stf_addpar (im, "DATAMAX", TY_REAL, 1, zero, pno)
+
+ do i = 1, ndim {
+ call sprintf (pname, SZ_KEYWORD, "CRPIX%d"); call pargi (i)
+ call stf_addpar (im, pname, TY_REAL, 1, zero, pno)
+ call sprintf (pname, SZ_KEYWORD, "CRVAL%d"); call pargi (i)
+ call stf_addpar (im, pname, TY_DOUBLE, 1, zero, pno)
+ call sprintf (pname, SZ_KEYWORD, "CTYPE%d"); call pargi (i)
+ call stf_addpar (im, pname, TY_CHAR, 8, "PIXEL", pno)
+
+ do j = 1, ndim {
+ call sprintf (pname, SZ_KEYWORD, "CD%d_%d")
+ call pargi (j)
+ call pargi (i)
+ if (i == j)
+ call stf_addpar (im, pname, TY_REAL, 1, one, pno)
+ else
+ call stf_addpar (im, pname, TY_REAL, 1, zero, pno)
+ }
+ }
+ }
+
+ # Compute the size of each group in the pixel file, in chars.
+ totpix = IM_LEN(im,1)
+ do i = 2, ndim
+ totpix = totpix * IM_LEN(im,i)
+
+ STF_SZGROUP(stf) = totpix * pix_size[IM_PIXTYPE(im)] +
+ STF_PSIZE(stf) / (SZB_CHAR * NBITS_BYTE)
+end
diff --git a/sys/imio/iki/stf/stfopen.x b/sys/imio/iki/stf/stfopen.x
new file mode 100644
index 00000000..016c557e
--- /dev/null
+++ b/sys/imio/iki/stf/stfopen.x
@@ -0,0 +1,225 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <syserr.h>
+include <error.h>
+include <imhdr.h>
+include <imio.h>
+include "stf.h"
+
+# STF_OPEN -- Open/create an STF group format image.
+
+procedure stf_open (kernel, im, o_im,
+ root, extn, ksection, gr_arg, gc_arg, acmode, status)
+
+int kernel #I IKI kernel
+pointer im #I image descriptor
+pointer o_im #I other descriptor for NEW_COPY image
+char root[ARB] #I root image name
+char extn[ARB] #I extension, if any
+char ksection[ARB] #I NOT USED
+int gr_arg #I index of group to be accessed
+int gc_arg #I number of groups in STF image
+int acmode #I access mode
+int status #O return value
+
+bool subimage
+pointer sp, fname, stf, stf_extn, ua, o_stf
+int group, gcount, newimage, gpb, hdr, o_stflen
+
+bool fnullfile(), envgetb()
+int open(), stropen(), access()
+errchk stf_initwcs, fmkcopy, calloc, realloc, syserrs
+define err_ 91
+
+begin
+ call smark (sp)
+ call salloc (fname, SZ_PATHNAME, TY_CHAR)
+ call salloc (stf_extn, MAX_LENEXTN, TY_CHAR)
+
+ ua = IM_USERAREA(im)
+
+ # Allocate internal STF image descriptor.
+ call calloc (stf, LEN_STFDES, TY_STRUCT)
+ IM_KDES(im) = stf
+
+ group = max (1, gr_arg)
+ gcount = max (group, gc_arg)
+
+ STF_GRARG(stf) = max (0, gr_arg)
+ STF_GROUP(stf) = group
+ STF_GCOUNT(stf) = gcount
+ STF_ACMODE(stf) = acmode
+ STF_PFD(stf) = NULL
+
+ # If a nonzero gcount is specified when a new-image or new-copy image
+ # is opened (e.g., [1/10] we assume that an entire new group format
+ # image is to be created with the given group count. If neither the
+ # group or gcount values are specified we assume that a new image is
+ # to be created. If the gcount field is zero (e.g., [1/0] or just [1])
+ # then we assume that the image already exists and that we are being
+ # asked to rewrite the indexed image.
+
+ newimage = NO
+ if (acmode == NEW_IMAGE || acmode == NEW_COPY)
+ if (gc_arg > 0 || (gr_arg <= 0 && gc_arg <= 0))
+ newimage = YES
+ STF_NEWIMAGE(stf) = newimage
+
+ # Generate full header file name.
+ if (extn[1] == EOS) {
+ call stf_gethdrextn (im, o_im, acmode, Memc[stf_extn], MAX_LENEXTN)
+ call iki_mkfname (root, Memc[stf_extn], Memc[fname], SZ_PATHNAME)
+ call strcpy (Memc[stf_extn], extn, MAX_LENEXTN)
+ } else
+ call iki_mkfname (root, extn, Memc[fname], SZ_PATHNAME)
+
+ call strcpy (Memc[fname], IM_HDRFILE(im), SZ_IMHDRFILE)
+
+ # Generate full pixel file name.
+ call stf_mkpixfname (root, extn, Memc[fname], SZ_PATHNAME)
+ call strcpy (Memc[fname], IM_PIXFILE(im), SZ_IMPIXFILE)
+
+ # Create and open the image header file if create a new physical
+ # image. If opening an existing image we do not open the header file
+ # here since the header may already be in the STF header cache.
+ # Since STF header files have a weird file type on some systems (VMS)
+ # we must create a new header file with FMKCOPY rather than OPEN.
+
+ if (STF_NEWIMAGE(stf) == YES && !fnullfile (IM_HDRFILE(im))) {
+ if (access (IM_HDRFILE(im), 0,0) == YES) {
+ subimage = (gr_arg > 0 && gr_arg <= gc_arg)
+ if (subimage || envgetb ("imclobber")) {
+ iferr (call delete (IM_PIXFILE(im)))
+ goto err_
+ iferr (call delete (IM_HDRFILE(im)))
+ goto err_
+ } else {
+ call mfree (stf, TY_STRUCT)
+ call syserrs (SYS_IKICLOB, IM_HDRFILE(im))
+ }
+ }
+ iferr (call fmkcopy (HDR_TEMPLATE, IM_HDRFILE(im)))
+ goto err_
+ iferr (IM_HFD(im) = open (IM_HDRFILE(im), READ_WRITE, TEXT_FILE))
+ goto err_
+ }
+
+ # If opening an existing image, read the image header into the STF
+ # image descriptor.
+
+ switch (acmode) {
+ case NEW_IMAGE:
+ # For group formatted images, open NEW_IMAGE can mean either
+ # creating a new group format image, or opening a new group
+ # within an existing group format image. The latter case is
+ # indicated by a group index greater than 1. If we are creating
+ # a new group format image, wait until the user has set up the
+ # dimension parameters before doing anything further (in stfopix).
+
+ if (STF_NEWIMAGE(stf) == NO)
+ iferr (call stf_rdheader (im, group, acmode))
+ goto err_
+
+ case NEW_COPY:
+ # Make sure the FITS encoded user area we inherited is blocked.
+
+ ### For now, always reblock the old header as the blocked flag
+ ### does not seem to be reliable and a header with variable length
+ ### lines can cause the header update to fail. This should be
+ ### fixed as a reblock of the full header is expensive.
+
+ ### if (IM_UABLOCKED(o_im) != YES)
+ call stf_reblock (im)
+
+ if (STF_NEWIMAGE(stf) == NO) {
+ # Open new group within existing GF image. The FITS header and
+ # GPB structure of the image being opened must be used, but the
+ # default data values for the GPB parameters are inherited from
+ # the image being copied.
+
+ # Filter the copied user area to retain only the GPB cards.
+ # Opening the user area on two string file descriptors is a
+ # bit tricky, but will work since fixed size cards are copied,
+ # and the EOS isn't written until close time.
+
+ if (IM_KDES(o_im) != NULL && IM_KERNEL(o_im) == IM_KERNEL(im)) {
+ hdr = stropen (Memc[ua], ARB, READ_ONLY)
+ gpb = stropen (Memc[ua], ARB, NEW_FILE)
+ call stf_copyfits (IM_KDES(o_im), hdr, gpb, NULL)
+ call close (gpb)
+ call close (hdr)
+ }
+
+ # Read in the FITS header of the new image after the inherited
+ # GPB data cards, and set up the STF descriptor for the new GPB
+ # as defined in the new FITS header.
+
+ iferr (call stf_rdheader (im, group, acmode))
+ goto err_
+
+ # Initialize the WCS description if this is not done by the
+ # inherited user header.
+
+ call stf_initwcs (im)
+
+ } else {
+ # Completely new copy of an existing image, which may or may
+ # not be an STF format image. IMIO has already copied the
+ # size parameters of the old image as well as the cards in the
+ # user area of the old image (but without leaving space for
+ # the GPB cards if not an STF image). Copy old STF descriptor
+ # if the old image is also an STF format image, to inherit
+ # GPB structure. Wait until opix time to init the rest of the
+ # descriptor.
+
+ if (IM_KDES(o_im) != NULL && IM_KERNEL(o_im) == IM_KERNEL(im)) {
+ o_stf = IM_KDES(o_im)
+ o_stflen = LEN_STFBASE + STF_PCOUNT(o_stf) * LEN_PDES
+ call amovi (Memi[o_stf], Memi[stf], o_stflen)
+ STF_ACMODE(stf) = acmode
+ STF_GROUP(stf) = group
+ STF_GCOUNT(stf) = gcount
+ STF_NEWIMAGE(stf) = newimage
+ STF_PFD(stf) = NULL
+ if (gcount > 1)
+ STF_GROUPS(stf) = YES
+ } else
+ STF_GROUPS(stf) = YES
+
+ # Inherit datatype of input template image if specified,
+ # otherwise default datatype to real.
+
+ if (IM_PIXTYPE(o_im) != NULL)
+ IM_PIXTYPE(im) = IM_PIXTYPE(o_im)
+ else
+ IM_PIXTYPE(im) = TY_REAL
+ }
+
+ default:
+ # Open an existing group within an existing image.
+ iferr (call stf_rdheader (im, group, acmode))
+ goto err_
+ }
+
+ # Set group number and count for the external world if this is a group
+ # format image.
+
+ if (STF_GROUPS(stf) == YES) {
+ IM_CLINDEX(im) = STF_GROUP(stf)
+ IM_CLSIZE(im) = STF_GCOUNT(stf)
+ }
+
+ # 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)
+ IM_KDES(im) = stf
+ status = OK
+
+ call sfree (sp)
+ return
+err_
+ status = ERR
+ call mfree (stf, TY_STRUCT)
+ call sfree (sp)
+end
diff --git a/sys/imio/iki/stf/stfopix.x b/sys/imio/iki/stf/stfopix.x
new file mode 100644
index 00000000..da353119
--- /dev/null
+++ b/sys/imio/iki/stf/stfopix.x
@@ -0,0 +1,202 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <syserr.h>
+include <imhdr.h>
+include <imio.h>
+include <fset.h>
+include <mach.h>
+include "stf.h"
+
+define NBITS_CHAR (SZB_CHAR * NBITS_BYTE)
+
+# STF_OPIX -- Open (or create) the pixel storage file. If the image header file
+# is `image.hhh' the associated pixel storage file will be `image.hhd' in the
+# same directory as the header file. STF_PFD is set if the pixel file is
+# physically open. IM_PFD is not set until we have been called by IMIO, since
+# we must be called to once set up all the descriptors, even if the pixel file
+# was already opened to read the GPB.
+#
+# dlb, 18-may-88: added code to zero out gpb's in multi-group image for groups
+# other than current; prevents strange numbers and when later programs try to
+# read the gpb of an otherwise uninitialized group of the image.
+# dlb, 29-dec-1988: added code to get default set of GPB parameters and
+# correctly initialize STF-kernel descriptor.
+
+procedure stf_opix (im, status)
+
+pointer im # image descriptor
+int status # return status
+
+int compress, blklen
+bool copy_of_stf_image
+int pfd, sz_gpb, group, i
+pointer stf, o_stf, o_im, ua, gpb
+long sz_pixfile, pixoff, totpix, offset
+
+int open()
+errchk open, fseti, falloc, seek, syserrs, imioff, calloc
+errchk write
+
+include <szpixtype.inc>
+
+begin
+ status = OK
+ if (IM_PFD(im) != NULL)
+ return
+
+ o_im = IM_OHDR(im)
+ stf = IM_KDES(im)
+ ua = IM_USERAREA(im)
+
+ pfd = STF_PFD(stf)
+ compress = YES
+ blklen = 1
+ pixoff = 1
+
+ switch (IM_ACMODE(im)) {
+ case READ_ONLY, READ_WRITE, WRITE_ONLY, APPEND:
+ if (pfd == NULL)
+ pfd = open (IM_PIXFILE(im), IM_ACMODE(im), BINARY_FILE)
+
+ case NEW_COPY, NEW_FILE:
+ # Initialize the IMIO and STF descriptors and allocate the pixel
+ # file.
+
+ if (STF_NEWIMAGE(stf) == YES) {
+ # Normalize IMIO header parameters for new image.
+ call imioff (im, pixoff, compress, blklen)
+
+ # Set up the required GPB parameters for the new image.
+ # Note - this call can change the STF pointer.
+
+ call stf_newimage (im)
+ stf = IM_KDES(im)
+
+ # Save the size of the old GPB user area header if we are
+ # making a new copy of an old STF format image.
+
+ copy_of_stf_image = false
+ if (IM_ACMODE(im) == NEW_COPY && o_im != NULL)
+ if (IM_KERNEL(o_im) == IM_KERNEL(im))
+ copy_of_stf_image = true
+
+ if (copy_of_stf_image) {
+ o_stf = IM_KDES(o_im)
+ STF_PCOUNT(stf) = STF_PCOUNT(o_stf)
+ STF_PSIZE(stf) = STF_PSIZE(o_stf)
+ }
+
+# Since the stf_mergegpb code below has been deactivated,
+# there is no need to do the complex and expensive spool/copy
+# operation below. (dct 1/4/90)
+# -------------------------------
+# # We have to have space for the GPB data cards at the beginning
+# # of the user area, so spool any existing user cards in a
+# # buffer and truncate the user area at the end of the GPB.
+#
+# ua_fd = stropen (Memc[ua+sz_gpbhdr], ARB, READ_ONLY)
+# spool = open ("opix_spool", READ_WRITE, SPOOL_FILE)
+# call fcopyo (ua_fd, spool)
+# call close (ua_fd)
+# Memc[ua+sz_gpbhdr] = EOS
+#
+# # Merge any extra GPB parameters from the old image into the
+# # GPB structure of the new image. The GPB data cards for
+# # these parameters should already be in the user area.
+# # Order the group parameters to match the ordering in the
+# # old image. NOTE: since the STF now copies all relevant
+# # GPB parameters from an old image into the new or
+# # generates a default standard set (in stf_newimage),
+# # the following is no longer necessary. Note that if we
+# # eventually may add parameters to the GPB, these routines
+# # will again be useful!
+#
+# #if (copy_of_stf_image) {
+# # call stf_mergegpb (im, o_im)
+# # call stf_ordergpb (o_stf, stf)
+# #}
+#
+# # Now append the spooled user header cards to the new user
+# # area following the GPB data cards, deleting any user cards
+# # which redefine GPB cards in the process.
+#
+# call seek (spool, BOFL)
+# ua_size = (IM_LENHDRMEM(im) - LEN_IMHDR) * SZ_STRUCT
+# ua_fd = stropen (Memc[ua], ua_size, APPEND)
+# call stf_copyfits (stf, spool, NULL, ua_fd)
+# call close (ua_fd)
+# call close (spool)
+#
+# # Compute the length of the new header
+# IM_HDRLEN(im) = LEN_IMHDR +
+# (strlen(Memc[ua]) + SZ_STRUCT-1) / SZ_STRUCT
+
+ # Open the new pixel storage file (preallocate space if
+ # enabled on local system). Save the physical pathname of
+ # the pixfile in the image header, in case "imdir$" changes.
+
+ sz_pixfile = STF_SZGROUP(stf) * STF_GCOUNT(stf)
+ call falloc (IM_PIXFILE(im), sz_pixfile)
+
+ # Zero out all remaining groups of the image
+ # Open pixel file if not already open
+
+ if (STF_PFD(stf) == NULL)
+ pfd = open (IM_PIXFILE(im), READ_WRITE, BINARY_FILE)
+
+ # Allocate a zeroed block of memory whose length is the same
+ # as that of the group parameter block
+
+ sz_gpb = STF_PSIZE(stf) / NBITS_BYTE / SZB_CHAR
+ call calloc (gpb, sz_gpb, TY_CHAR)
+
+ # Zero out every group except the current one.
+ do group = 1, STF_GCOUNT(stf) {
+ if (group != STF_GROUP(stf)) {
+ offset = (group * STF_SZGROUP(stf) + 1) - sz_gpb
+ call seek (pfd, offset)
+ call write (pfd, Memc[gpb], sz_gpb)
+ }
+ }
+
+ # Free the block of memory.
+ call mfree (gpb, TY_CHAR)
+
+ } else {
+ # If we are writing to a group of an existing multigroup image,
+ # verify that the important image parameters have not been
+ # changed.
+
+ if (STF_NAXIS(stf) != IM_NDIM(im))
+ call syserrs (SYS_IMGSZNEQ, IM_NAME(im))
+ do i = 1, IM_NDIM(im)
+ if (STF_LENAXIS(stf,i) != IM_LEN(im,i))
+ call syserrs (SYS_IMGSZNEQ, IM_NAME(im))
+
+ # Added 5/15/87--dlb to get correct size of each data portion
+ # of a group if image opened NEW_COPY and input file was a
+ # template of a different dimensionality used to get GPB.
+ # Compute the size of each group in the pixel file, in chars.
+
+ totpix = IM_LEN(im,1)
+ do i = 2, IM_NDIM(im)
+ totpix = totpix * IM_LEN(im,i)
+
+ STF_SZGROUP(stf) = totpix * pix_size[IM_PIXTYPE(im)] +
+ STF_PSIZE(stf) / (SZB_CHAR * NBITS_BYTE)
+ }
+
+ if (pfd == NULL)
+ pfd = open (IM_PIXFILE(im), READ_WRITE, BINARY_FILE)
+
+ # Tell IMIO where the pixels are.
+ pixoff = (STF_GROUP(stf) - 1) * STF_SZGROUP(stf) + 1
+ call imioff (im, pixoff, compress, blklen)
+
+ default:
+ call imerr (IM_NAME(im), SYS_IMACMODE)
+ }
+
+ STF_PFD(stf) = pfd
+ IM_PFD(im) = pfd
+end
diff --git a/sys/imio/iki/stf/stfordgpb.x b/sys/imio/iki/stf/stfordgpb.x
new file mode 100644
index 00000000..7099e106
--- /dev/null
+++ b/sys/imio/iki/stf/stfordgpb.x
@@ -0,0 +1,64 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include "stf.h"
+
+# STF_ORDERGPB -- Order the GPB, putting the group parameters in the
+# new image in the same order as in the old image.
+# NOTE: no longer called by stf_opix; save this code for future use!
+# <dlb--11/4/87>
+
+procedure stf_ordergpb (o_stf, n_stf)
+
+pointer o_stf # STF descriptor of old image
+pointer n_stf # STF descriptor of new image
+
+pointer sp, temp_pdes, pp, o_plist, n_plist
+int o_pcount, n_pcount, otop, ntop, op, np, offset, sz_param, pn
+bool streq()
+
+begin
+ o_pcount = STF_PCOUNT(o_stf)
+ n_pcount = STF_PCOUNT(n_stf)
+ if (o_pcount <= 0)
+ return
+
+ call smark (sp)
+ call salloc (temp_pdes, LEN_PDES, TY_STRUCT)
+
+ o_plist = STF_PDES(o_stf,1)
+ n_plist = STF_PDES(n_stf,1)
+ otop = (o_pcount * LEN_PDES)
+ ntop = (n_pcount * LEN_PDES)
+
+ # Search the new parameter list for a parameter with the same name
+ # as a parameter in the old parameter list. When a match is found,
+ # move the new parameter into the same position as it is in the
+ # old parameter list.
+
+ for (op=0; op < otop; op=op+LEN_PDES)
+ for (np=op; np < ntop; np=np+LEN_PDES)
+ if (streq (P_PTYPE(o_plist+op), P_PTYPE(n_plist+np))) {
+ if (op != np) {
+ # Swap parameters between old and new positions
+ call amovi (Memi[n_plist+op], Memi[temp_pdes],
+ LEN_PDES)
+ call amovi (Memi[n_plist+np], Memi[n_plist+op],
+ LEN_PDES)
+ call amovi (Memi[temp_pdes], Memi[n_plist+np],
+ LEN_PDES)
+ }
+ break
+ }
+
+ # Update the field offsets.
+ offset = 0
+ for (pn=1; pn <= n_pcount; pn=pn+1) {
+ pp = STF_PDES(n_stf,pn)
+ P_OFFSET(pp) = offset
+ sz_param = P_PSIZE(pp) / NBITS_BYTE / SZB_CHAR
+ offset = offset + sz_param
+ }
+
+ call sfree (sp)
+end
diff --git a/sys/imio/iki/stf/stfrdhdr.x b/sys/imio/iki/stf/stfrdhdr.x
new file mode 100644
index 00000000..2c11fec9
--- /dev/null
+++ b/sys/imio/iki/stf/stfrdhdr.x
@@ -0,0 +1,186 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <finfo.h>
+include <imhdr.h>
+include <imio.h>
+include <mach.h>
+include "stf.h"
+
+# STF_RDHEADER -- Read the STF format image header for a single group into the
+# IMIO descriptor. The standard fields are processed into the fields of the
+# descriptor. The GPB binary parameters are encoded as FITS cards and placed
+# in the IMIO user area, followed by all extra cards in the FITS format STF
+# group header. Note that no distinction is made between the common FITS
+# keywords and the GPB group parameters at the IMIO level and above.
+
+procedure stf_rdheader (im, group, acmode)
+
+pointer im # image descriptor
+int group # group to be accessed
+int acmode # access mode
+
+long pixoff
+long fi[LEN_FINFO]
+real datamin, datamax
+pointer sp, stf, lbuf, root, extn, op
+int compress, devblksz, ival, ch, i , junk
+int fits, fitslen, sz_userarea, sz_gpbhdr, len_hdrmem
+long totpix, mtime, ctime
+
+real imgetr()
+int fnroot(), strlen(), finfo(), imaccf()
+errchk stf_rfitshdr, stf_rgpb, open, realloc, imaddb, imaddi, imgetr
+
+include <szpixtype.inc>
+
+begin
+ call smark (sp)
+ call salloc (lbuf, SZ_LINE, TY_CHAR)
+ call salloc (root, SZ_FNAME, TY_CHAR)
+ call salloc (extn, SZ_FNAME, TY_CHAR)
+
+ stf = IM_KDES(im)
+
+ # Read the FITS header, setting the values of all reserved fields
+ # in the STF descriptor and saving all the user FITS cards in the
+ # save buffer "fits".
+
+ call stf_rfitshdr (im, fits, fitslen)
+
+ # Process the reserved keywords (set in the STF descriptor) into the
+ # corresponding fields of the IMIO descriptor.
+
+ # Set group keywords if STF_GROUPS is NO (BPS 12.06.91).
+ if (STF_GROUPS(stf) == NO) {
+ STF_GCOUNT(stf) = 1
+ STF_PCOUNT(stf) = 0
+ STF_PSIZE(stf) = 0
+ }
+
+ if (acmode != NEW_COPY) {
+ IM_NDIM(im) = STF_NAXIS(stf) # IM_NDIM
+ do ival = 1, IM_MAXDIM # IM_LEN
+ IM_LEN(im,ival) = STF_LENAXIS(stf,ival)
+ }
+
+ ch = STF_DATATYPE(stf) # IM_PIXTYPE
+ switch (STF_BITPIX(stf)) {
+ case 16:
+ if (ch == 'U')
+ ival = TY_USHORT
+ else
+ ival = TY_SHORT
+ case 32:
+ if (ch == 'R')
+ ival = TY_REAL
+ else
+ ival = TY_LONG
+ case 64:
+ if (ch == 'R')
+ ival = TY_DOUBLE
+ else
+ ival = TY_COMPLEX
+ default:
+ ival = ERR
+ }
+ IM_PIXTYPE(im) = ival
+
+ call iki_parse (IM_HDRFILE(im), Memc[root], Memc[extn])
+ call stf_mkpixfname (Memc[root], Memc[extn], IM_PIXFILE(im),
+ SZ_IMPIXFILE)
+
+ if (finfo (IM_PIXFILE(im), fi) != ERR) {
+ mtime = FI_MTIME(fi)
+ ctime = FI_CTIME(fi)
+ }
+
+ IM_NBPIX(im) = 0 # no. bad pixels
+ IM_CTIME(im) = ctime # creation time
+ IM_MTIME(im) = mtime # modify time
+ IM_LIMTIME(im) = mtime - 1 # time max/min last updated
+ IM_UABLOCKED(im) = YES # ua cards blocked to 80 chars
+
+ IM_HISTORY(im) = EOS
+ junk = fnroot (IM_HDRFILE(im), Memc[lbuf], SZ_LINE)
+ call strupr (Memc[lbuf])
+ call sprintf (IM_TITLE(im), SZ_IMTITLE, "%s[%d/%d]")
+ call pargstr (Memc[lbuf])
+ call pargi (STF_GROUP(stf))
+ call pargi (STF_GCOUNT(stf))
+
+ # Compute the size of each group in the pixel file, in chars.
+ totpix = IM_LEN(im,1)
+ do i = 2, IM_NDIM(im)
+ totpix = totpix * IM_LEN(im,i)
+
+ STF_SZGROUP(stf) = totpix * pix_size[IM_PIXTYPE(im)] +
+ STF_PSIZE(stf) / (SZB_CHAR * NBITS_BYTE)
+
+ # Write GPB related cards to the beginning of the IMIO user area.
+ call imaddb (im, "GROUPS", STF_GROUPS(stf) == YES)
+ call imaddi (im, "GCOUNT", STF_GCOUNT(stf))
+ call imaddi (im, "PCOUNT", STF_PCOUNT(stf))
+ call imaddi (im, "PSIZE", STF_PSIZE(stf))
+
+ # Extract the group parameter block from the pixfile, encoding the
+ # group parameters as FITS cards and appending to the cards above.
+ # Get the values of DATAMIN and DATAMAX from the GPB so that we can
+ # update the IMIO min/max fields.
+
+ call stf_rgpb (im, group, acmode, datamin, datamax)
+
+ # Reallocate the image descriptor to allow space for the spooled user
+ # FITS cards plus a little extra for new parameters.
+
+ sz_gpbhdr = strlen (Memc[IM_USERAREA(im)])
+ sz_userarea = sz_gpbhdr + fitslen + SZ_EXTRASPACE
+
+ IM_HDRLEN(im) = LEN_IMHDR +
+ (sz_userarea - SZ_EXTRASPACE + SZ_MII_INT-1) / SZ_MII_INT
+ len_hdrmem = LEN_IMHDR +
+ (sz_userarea+1 + SZ_MII_INT-1) / SZ_MII_INT
+
+ if (IM_LENHDRMEM(im) < len_hdrmem) {
+ IM_LENHDRMEM(im) = len_hdrmem
+ call realloc (im, IM_LENHDRMEM(im) + LEN_IMDES, TY_STRUCT)
+ }
+
+ # Append the saved FITS cards from the STF header to the user area.
+ # Any cards which redefine GPB cards were already deleted when the
+ # fits save buffer was created (we don't want the GPB cards since
+ # we already output a FITS card for each GPB parameter above).
+
+ op = IM_USERAREA(im) + sz_gpbhdr
+ call amovc (Memc[fits], Memc[op], fitslen+1)
+
+ # Set the IMIO min/max fields. If the GPB datamin >= datamax the
+ # values are invalidated by setting IM_LIMTIME to before the image
+ # modification time. Although datamin/datamax were returned by
+ # stg_rgpb above, we refetch the values here to pick up the values
+ # from the spooled main header in case there were no entries for
+ # these keywords in the GPB (if there are values in the GPB they
+ # will override those in the main header).
+
+ if (imaccf (im, "DATAMIN") == YES)
+ datamin = imgetr (im, "DATAMIN")
+ if (imaccf (im, "DATAMAX") == YES)
+ datamax = imgetr (im, "DATAMAX")
+
+ IM_MIN(im) = datamin
+ IM_MAX(im) = datamax
+ if (datamin < datamax)
+ IM_LIMTIME(im) = IM_MTIME(im) + 1
+ else
+ IM_LIMTIME(im) = IM_MTIME(im) - 1
+
+ # Call up IMIO set set up the remaining image header fields used to
+ # define the physical offsets of the pixels in the pixfile.
+
+ compress = YES # do not align image lines on blocks
+ devblksz = 1 # disable all alignment
+
+ pixoff = (group - 1) * STF_SZGROUP(stf) + 1
+ call imioff (im, pixoff, compress, devblksz)
+
+ call sfree (sp)
+end
diff --git a/sys/imio/iki/stf/stfreblk.x b/sys/imio/iki/stf/stfreblk.x
new file mode 100644
index 00000000..9519bd08
--- /dev/null
+++ b/sys/imio/iki/stf/stfreblk.x
@@ -0,0 +1,65 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <imhdr.h>
+include <imio.h>
+include "stf.h"
+
+# STF_REBLOCK -- If the user area is not blocked to fixed length records, e.g.,
+# as is possible in a new copy image, reblock it fixed length.
+
+procedure stf_reblock (im)
+
+pointer im # image descriptor
+
+pointer sp, lbuf, op, ua
+int fd, spool, nlines, nchars, sz_userarea, len_hdrmem
+errchk stropen, open, getline, putline, realloc, seek, fcopyo
+int open(), stropen(), getline()
+
+begin
+ call smark (sp)
+ call salloc (lbuf, SZ_LINE, TY_CHAR)
+
+ ua = IM_USERAREA(im)
+ fd = stropen (Memc[ua], ARB, READ_ONLY)
+ spool = open ("rb_spool", READ_WRITE, SPOOL_FILE)
+
+ # Reblock into a spool file, counting the lines.
+ for (nlines=0; ; nlines=nlines+1) {
+ nchars = getline (fd, Memc[lbuf])
+ if (nchars <= 0)
+ break
+
+ for (op=nchars; op <= FITS_RECLEN; op=op+1)
+ Memc[lbuf+op-1] = ' '
+ Memc[lbuf+FITS_RECLEN] = '\n'
+ Memc[lbuf+FITS_RECLEN+1] = EOS
+
+ call putline (spool, Memc[lbuf])
+ }
+
+ call close (fd)
+
+ # Reallocate header the right size.
+ sz_userarea = nlines * (FITS_RECLEN+1) + SZ_EXTRASPACE
+
+ IM_HDRLEN(im) = LEN_IMHDR +
+ (sz_userarea - SZ_EXTRASPACE + SZ_MII_INT-1) / SZ_MII_INT
+ len_hdrmem = LEN_IMHDR +
+ (sz_userarea+1 + SZ_MII_INT-1) / SZ_MII_INT
+
+ if (IM_LENHDRMEM(im) < len_hdrmem) {
+ IM_LENHDRMEM(im) = len_hdrmem
+ call realloc (im, IM_LENHDRMEM(im) + LEN_IMDES, TY_STRUCT)
+ }
+
+ # Move spooled data back to user area.
+ ua = IM_USERAREA(im)
+ fd = stropen (Memc[ua], sz_userarea, NEW_FILE)
+ call seek (spool, BOFL)
+ call fcopyo (spool, fd)
+
+ call close (fd)
+ call close (spool)
+ call sfree (sp)
+end
diff --git a/sys/imio/iki/stf/stfrename.x b/sys/imio/iki/stf/stfrename.x
new file mode 100644
index 00000000..0d3c43fd
--- /dev/null
+++ b/sys/imio/iki/stf/stfrename.x
@@ -0,0 +1,49 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <error.h>
+include "stf.h"
+
+# STF_RENAME -- Rename an image. A special operator is required since the image
+# is stored as two files.
+#
+# [NOTE] - Name changed to `rname' rather than `rename' to avoid a name
+# collision with the SYMTAB procedure `stfree' (first such collision!).
+
+procedure stf_rname (kernel, oroot, oextn, nroot, nextn, status)
+
+int kernel #I IKI kernel
+char oroot[ARB] # old image root name
+char oextn[ARB] # old image extn
+char nroot[ARB] # new image root name
+char nextn[ARB] # old image extn
+int status
+
+pointer sp
+pointer ohdr_fname, opix_fname, nhdr_fname, npix_fname
+bool streq()
+
+begin
+ call smark (sp)
+ call salloc (ohdr_fname, SZ_PATHNAME, TY_CHAR)
+ call salloc (opix_fname, SZ_PATHNAME, TY_CHAR)
+ call salloc (nhdr_fname, SZ_PATHNAME, TY_CHAR)
+ call salloc (npix_fname, SZ_PATHNAME, TY_CHAR)
+
+ # Generate filenames.
+ call iki_mkfname (oroot, oextn, Memc[ohdr_fname], SZ_PATHNAME)
+ call iki_mkfname (nroot, nextn, Memc[nhdr_fname], SZ_PATHNAME)
+
+ if (!streq (Memc[ohdr_fname], Memc[nhdr_fname])) {
+ call stf_mkpixfname (oroot, oextn, Memc[opix_fname], SZ_PATHNAME)
+ call stf_mkpixfname (nroot, nextn, Memc[npix_fname], SZ_PATHNAME)
+
+ # If the header cannot be renamed, don't leave the pixfile alone.
+ iferr (call rename (Memc[ohdr_fname], Memc[nhdr_fname]))
+ call erract (EA_WARN)
+ else iferr (call rename (Memc[opix_fname], Memc[npix_fname]))
+ call erract (EA_WARN)
+ }
+
+ call sfree (sp)
+ status = OK
+end
diff --git a/sys/imio/iki/stf/stfrfits.x b/sys/imio/iki/stf/stfrfits.x
new file mode 100644
index 00000000..8ec9e9b0
--- /dev/null
+++ b/sys/imio/iki/stf/stfrfits.x
@@ -0,0 +1,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
diff --git a/sys/imio/iki/stf/stfrgpb.x b/sys/imio/iki/stf/stfrgpb.x
new file mode 100644
index 00000000..15c4da0a
--- /dev/null
+++ b/sys/imio/iki/stf/stfrgpb.x
@@ -0,0 +1,179 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <imhdr.h>
+include <imio.h>
+include <mach.h>
+include "stf.h"
+
+# STF_RGPB -- Read the group data block into the first few cards of the user
+# area of the IMIO image header. The GPB is stored as a binary data structure
+# in the STF pixfile. The values of the standard GPB parameters DATAMIN and
+# DATAMAX are returned as output arguments.
+#
+# DLB--11/03/87: Made changes to allow i*2 and i*4 integer parameters in GPB.
+# DLB--11/11/87: Changed calculation of character string length in GPB to
+# avoid integer truncation error by using P_PSIZE directly.
+
+procedure stf_rgpb (im, group, acmode, datamin, datamax)
+
+pointer im # IMIO image descriptor
+int group # group to be accessed
+int acmode # image access mode
+real datamin, datamax # min,max pixel values from GPB
+
+real rval
+double dval
+short sval
+long lval, offset
+bool bval, newgroup
+pointer sp, stf, gpb, lbuf, pp
+int pfd, pn, sz_param, sz_gpb
+errchk imaddb, imadds, imaddl, imaddr, imaddd, imastr
+errchk imputd, impstr, open, read
+int open(), read(), imaccf()
+real imgetr()
+
+string readerr "cannot read group data block - no such group?"
+string badtype "illegal group data parameter datatype"
+string nogroup "group index out of range"
+define minmax_ 91
+
+begin
+ call smark (sp)
+ call salloc (lbuf, SZ_LINE, TY_CHAR)
+
+ stf = IM_KDES(im)
+ pfd = STF_PFD(stf)
+
+ # Verify that the given group exists.
+ if (group < 1 || group > STF_GCOUNT(stf))
+ call error (1, nogroup)
+
+ # Skip ahead if there is no group parameter block.
+ if (STF_PSIZE(stf) == 0)
+ goto minmax_
+
+ # Open the pixel file if not already open.
+ if (pfd == NULL) {
+ iferr {
+ if (IM_ACMODE(im) == READ_ONLY)
+ pfd = open (IM_PIXFILE(im), READ_ONLY, BINARY_FILE)
+ else
+ pfd = open (IM_PIXFILE(im), READ_WRITE, BINARY_FILE)
+ STF_PFD(stf) = pfd
+ } then {
+ call eprintf ("Warning: Cannot open pixfile to read GPB (%s)\n")
+ call pargstr (IM_NAME(im))
+ pfd = NULL
+ }
+ }
+
+ # Allocate a buffer for the GPB.
+ sz_gpb = STF_PSIZE(stf) / NBITS_BYTE / SZB_CHAR
+ call salloc (gpb, sz_gpb, TY_CHAR)
+
+ # Read the GPB into a buffer. The GPB is located at the very end of
+ # the data storage area for the group. If we are opening a new,
+ # uninitialized group (acmode = new_image or new_copy), do not
+ # physically read the GPB as it is will be uninitialized data.
+
+ newgroup = (acmode == NEW_IMAGE || acmode == NEW_COPY || pfd == NULL)
+ if (newgroup)
+ call aclrc (Memc[gpb], sz_gpb)
+ else {
+ offset = (group * STF_SZGROUP(stf) + 1) - sz_gpb
+ call seek (pfd, offset)
+ if (read (pfd, Memc[gpb], sz_gpb) != sz_gpb)
+ call error (1, readerr)
+ }
+
+ # Extract the binary value of each parameter in the GPB and encode it
+ # in FITS format in the IMIO user area.
+
+ offset = 0
+ for (pn=1; pn <= STF_PCOUNT(stf); pn=pn+1) {
+ pp = STF_PDES(stf,pn)
+
+ # Fill in the unitialized fields of the GPB parameter descriptor.
+ P_OFFSET(pp) = offset
+ sz_param = P_PSIZE(pp) / NBITS_BYTE / SZB_CHAR
+
+ switch (P_PDTYPE(pp)) {
+ # changed case for int to short and long--dlb 11/3/87
+ case 'I':
+ if (sz_param == SZ_SHORT)
+ P_SPPTYPE(pp) = TY_SHORT
+ else
+ P_SPPTYPE(pp) = TY_LONG
+ P_LEN(pp) = 1
+ case 'R':
+ if (sz_param == SZ_REAL)
+ P_SPPTYPE(pp) = TY_REAL
+ else
+ P_SPPTYPE(pp) = TY_DOUBLE
+ P_LEN(pp) = 1
+ case 'C':
+ P_SPPTYPE(pp) = TY_CHAR
+ # calculate length directly from PSIZE to avoid truncation error
+ P_LEN(pp) = min (SZ_LINE, P_PSIZE(pp) / NBITS_BYTE)
+ case 'L':
+ P_SPPTYPE(pp) = TY_BOOL
+ P_LEN(pp) = 1
+ default:
+ call error (1, badtype)
+ }
+
+ # Extract the binary parameter value and add a FITS encoded card
+ # to the IMIO user area. In the case of a new copy image, the
+ # GPB values will already be in the image header, do not modify
+ # the parameter value, but add the parameter if it was not
+ # inherited from the old image.
+
+ if (acmode != NEW_COPY || imaccf (im, P_PTYPE(pp)) == NO) {
+ switch (P_SPPTYPE(pp)) {
+ case TY_BOOL:
+ if (SZ_INT != SZ_INT32)
+ call amovc (Memc[gpb+offset], bval, SZ_INT32)
+ else
+ call amovc (Memc[gpb+offset], bval, SZ_BOOL)
+ call imaddb (im, P_PTYPE(pp), bval)
+ case TY_SHORT:
+ call amovc (Memc[gpb+offset], sval, SZ_SHORT)
+ call imadds (im, P_PTYPE(pp), sval)
+ case TY_LONG:
+ if (SZ_INT != SZ_INT32)
+ call amovc (Memc[gpb+offset], lval, SZ_INT32)
+ else
+ call amovc (Memc[gpb+offset], lval, SZ_LONG)
+ call imaddl (im, P_PTYPE(pp), lval)
+ case TY_REAL:
+ call amovc (Memc[gpb+offset], rval, SZ_REAL)
+ call imaddr (im, P_PTYPE(pp), rval)
+ case TY_DOUBLE:
+ call amovc (Memc[gpb+offset], dval, SZ_DOUBLE)
+ call imaddd (im, P_PTYPE(pp), dval)
+ case TY_CHAR:
+ call chrupk (Memc[gpb+offset], 1, Memc[lbuf], 1, P_LEN(pp))
+ Memc[lbuf+P_LEN(pp)] = EOS
+ call imastr (im, P_PTYPE(pp), Memc[lbuf])
+ default:
+ call error (1, badtype)
+ }
+ }
+
+ offset = offset + sz_param
+ }
+
+minmax_
+ # Return DATAMIN, DATAMAX. This is done by searching the user area so
+ # that ordinary keywords may be used to set datamin and datamax if the
+ # GPB is not used.
+
+ datamin = 0.0; datamax = 0.0
+ if (imaccf (im, "DATAMIN") == YES)
+ datamin = imgetr (im, "DATAMIN")
+ if (imaccf (im, "DATAMAX") == YES)
+ datamax = imgetr (im, "DATAMAX")
+
+ call sfree (sp)
+end
diff --git a/sys/imio/iki/stf/stfupdhdr.x b/sys/imio/iki/stf/stfupdhdr.x
new file mode 100644
index 00000000..a4519c24
--- /dev/null
+++ b/sys/imio/iki/stf/stfupdhdr.x
@@ -0,0 +1,60 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <syserr.h>
+include <imhdr.h>
+include <imio.h>
+include "stf.h"
+
+# STF_UPDHDR -- Update the STF/GEIS format image header.
+
+procedure stf_updhdr (im, status)
+
+pointer im # image descriptor
+int status # return status
+
+pointer stf
+int acmode
+real datamin, datamax
+errchk imerr, imputr, stf_wgpb
+
+begin
+ acmode = IM_ACMODE(im)
+ status = OK
+ stf = IM_KDES(im)
+
+ if (acmode == READ_ONLY)
+ call imerr (IM_NAME(im), SYS_IMUPIMHDR)
+
+ # Compute the values of DATAMIN and DATAMAX.
+ if (IM_LIMTIME(im) == 0 || IM_LIMTIME(im) < IM_MTIME(im)) {
+ datamin = 0.
+ datamax = 0.
+ } else {
+ datamin = IM_MIN(im)
+ datamax = IM_MAX(im)
+ }
+
+ # Update the group parameter block.
+ call stf_wgpb (im, STF_GROUP(stf), datamin, datamax)
+
+# # Update the FITS header file, unless we are writing to a new group
+# # in an existing group format image, in which case only the GPB is
+# # updated.
+#
+# if (acmode != NEW_IMAGE && acmode != NEW_COPY)
+# call stf_wfitshdr (im)
+# else if (STF_NEWIMAGE(stf) == YES)
+# call stf_wfitshdr (im)
+
+ # The new strategy for FITS header updates is to always update, unless
+ # we are explicitly updating an existing group of a multigroup image.
+ # Hence, the FITS header is always updated for an STF image with only
+ # one group, or when writing the first group of a new STF imagefile.
+ # The FITS header of an existing STF multigroup image can still be
+ # updated, but only if the image is not opened to any particular group,
+ # e.g., as "pix" rather than "pix[n]", N > 0. NEW_[IMAGE|COPY] or
+ # READ_WRITE access to "pix[n]" will update only the GPB header.
+
+ if (STF_NEWIMAGE(stf)==YES || STF_GCOUNT(stf)<=1 || STF_GRARG(stf)==0)
+ call stf_wfitshdr (im)
+end
diff --git a/sys/imio/iki/stf/stfwfits.x b/sys/imio/iki/stf/stfwfits.x
new file mode 100644
index 00000000..c444a235
--- /dev/null
+++ b/sys/imio/iki/stf/stfwfits.x
@@ -0,0 +1,147 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <error.h>
+include <imhdr.h>
+include <imio.h>
+include <fio.h>
+include "stf.h"
+
+# STF_WFITSHDR -- Update the FITS header file. This is done by writing an
+# entire new header file and then replacing the old header file with the
+# new one. This is necessary since the header file is a text file and text
+# files cannot be randomly updated.
+
+procedure stf_wfitshdr (im)
+
+pointer im # image descriptor
+
+pointer sp, fname, lbuf, stf, pp
+int in, out, pn, junk, i, width
+
+bool fnullfile()
+int stropen(), open(), protect(), strlen() #ditto-dlb
+errchk fmkcopy, open, stropen, fcopyo, fprintf
+
+begin
+ if (fnullfile (IM_HDRFILE(im)))
+ return
+
+ call smark (sp)
+ call salloc (fname, SZ_PATHNAME, TY_CHAR)
+ call salloc (lbuf, SZ_LINE, TY_CHAR)
+
+ stf = IM_KDES(im)
+
+ # Open a new header file with a unique, temporary name. Make a copy
+ # of the template file rather than of the old header file. Since
+ # we also block header lines out to 80 chars automatically, this
+ # means that we can read any old text file but will always generate
+ # a new header file of the standard type when the header is updated.
+
+ call mktemp (IM_HDRFILE(im), Memc[fname], SZ_FNAME)
+ call fmkcopy (HDR_TEMPLATE, Memc[fname])
+ out = open (Memc[fname], APPEND, TEXT_FILE)
+
+ # Write out the standard, reserved header parameters.
+
+ call fprintf (out, "SIMPLE =%21s /%81t\n")
+ call pargstr ("F")
+ call fprintf (out, "BITPIX =%21d /%81t\n")
+ call pargi (STF_BITPIX(stf))
+
+ # We want to get the full string length or 8 characters,
+ # whichever is greater--6/25/87, dlb
+
+ call fprintf (out, "DATATYPE= '%*.*s'%32t/%81t\n")
+ width = max(8, strlen(STF_DATATYPE(STF)))
+ call pargi (-width) # force left-justified field
+ call pargi (width)
+ call pargstr (STF_DATATYPE(stf))
+
+ call fprintf (out, "NAXIS =%21d /%81t\n")
+ call pargi (STF_NAXIS(stf))
+ do i = 1, STF_NAXIS(stf) {
+ call fprintf (out, "NAXIS%d%9t=%21d /%81t\n")
+ call pargi (i)
+ call pargi (STF_LENAXIS(stf,i))
+ }
+
+ call fprintf (out, "GROUPS =%21s /%81t\n")
+ if (STF_GROUPS(stf) == YES)
+ call pargstr ("T")
+ else
+ call pargstr ("F")
+
+ # Changed order of the following three cards to conform
+ # to SOGS expectations--dlb, 7/14/87
+ # Only write group keywords if STF_GROUPS is YES (BPS 12.06.91)
+
+ if (STF_GROUPS(stf) == YES) {
+ call fprintf (out, "GCOUNT =%21d /%81t\n")
+ call pargi (STF_GCOUNT(stf))
+ call fprintf (out, "PCOUNT =%21d /%81t\n")
+ call pargi (STF_PCOUNT(stf))
+ call fprintf (out, "PSIZE =%21d /%81t\n")
+ call pargi (STF_PSIZE(stf))
+ }
+
+ # Add cards defining the fields of the group parameter block. Each
+ # field requires three cards.
+
+ for (pn=1; pn <= STF_PCOUNT(stf); pn=pn+1) {
+ pp = STF_PDES(stf,pn)
+
+ # PTYPE MUST be 8 characters or less.
+ call fprintf (out, "PTYPE%d%9t= '%-8.8s'%32t/%s%81t\n")
+ call pargi (pn)
+ call pargstr (P_PTYPE(pp))
+ call pargstr (P_COMMENT(pp))
+
+ # Need width for string--6/26/87, dlb
+ call fprintf (out, "PDTYPE%d%9t= '%-*.*s'%32t/%81t\n")
+ call pargi (pn)
+ width = max (8, strlen(P_PDTYPE(pp)))
+ call pargi (-width) # force left-justified field
+ call pargi (width)
+ call pargstr (P_PDTYPE(pp))
+
+ call fprintf (out, "PSIZE%d%9t=%21d /%81t\n")
+ call pargi (pn)
+ call pargi (P_PSIZE(pp))
+ }
+
+ # Add the contents of the IMIO user area, excluding the cards used
+ # to represent GPB parameters.
+
+ in = stropen (Memc[IM_USERAREA(im)], ARB, READ_ONLY)
+ call stf_copyfits (stf, in, NULL, out)
+ call close (in)
+
+ # End of FITS header.
+ call fprintf (out, "END%81t\n")
+ call close (out)
+
+ # Replace the original header file with the new one, even if the
+ # original header is a protected file. Transfer any file protection
+ # to the new file.
+
+ if (IM_HFD(im) != NULL)
+ call close (IM_HFD(im))
+
+ if (protect (IM_HDRFILE(im), QUERY_PROTECTION) == YES) {
+ iferr (junk = protect (IM_HDRFILE(im), REMOVE_PROTECTION))
+ call erract (EA_ERROR)
+ iferr (junk = protect (Memc[fname], SET_PROTECTION))
+ call erract (EA_ERROR)
+ }
+
+ iferr (call delete (IM_HDRFILE(im)))
+ call erract (EA_ERROR)
+ iferr (call rename (Memc[fname], IM_HDRFILE(im)))
+ call erract (EA_ERROR)
+
+ if (IM_HFD(im) != NULL)
+ IM_HFD(im) = open (IM_HDRFILE(im), READ_ONLY, TEXT_FILE)
+
+ call sfree (sp)
+end
diff --git a/sys/imio/iki/stf/stfwgpb.x b/sys/imio/iki/stf/stfwgpb.x
new file mode 100644
index 00000000..3a9e8fe8
--- /dev/null
+++ b/sys/imio/iki/stf/stfwgpb.x
@@ -0,0 +1,174 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <error.h>
+include <imhdr.h>
+include <imio.h>
+include <mach.h>
+include "stf.h"
+
+# STF_WGPB -- Write the group parameter block data back into the pixel file.
+# The GPB is described by a structure member list in the STF descriptor.
+# The values of the GPB parameters are encoded as FITS cards in the user
+# area of the IMIO descriptor.
+#
+# DLB--11/3/87: Made changes to allow i*2 and i*4 integer parameters in gpb.
+
+procedure stf_wgpb (im, group, datamin, datamax)
+
+pointer im # IMIO image descriptor
+int group # group to be accessed
+real datamin, datamax # new min, max pixel values
+
+long offset
+pointer sp, stf, gpb, lbuf, pp, op
+int pfd, pn, sz_param, sz_gpb, i
+
+int open(), strlen()
+bool bval, imgetb()
+# changed to short and long for short integers in gpb
+short sval, imgets()
+long lval, imgetl()
+#
+real rval, imgetr()
+double dval, imgetd()
+errchk open, seek
+int imaccf()
+
+string writerr "cannot update group parameter block"
+string badtype "illegal group data parameter datatype"
+
+begin
+ call smark (sp)
+ call salloc (lbuf, SZ_LINE, TY_CHAR)
+
+ stf = IM_KDES(im)
+ pfd = STF_PFD(stf)
+
+ # Not all images have group parameter blocks.
+ if (STF_PSIZE(stf) == 0) {
+ call sfree (sp)
+ return
+ }
+
+ # Open the pixel file if not already open.
+ if (pfd == NULL) {
+ pfd = open (IM_PIXFILE(im), READ_WRITE, BINARY_FILE)
+ STF_PFD(stf) = pfd
+ }
+
+ # Update the values of DATAMIN, DATAMAX.
+ if (imaccf (im, "DATAMIN") == YES &&
+ imaccf (im, "DATAMAX") == YES) {
+
+ iferr {
+ call imputr (im, "DATAMIN", datamin)
+ call imputr (im, "DATAMAX", datamax)
+ } then
+ call erract (EA_WARN)
+ }
+
+ # Allocate a buffer for the GPB.
+ sz_gpb = STF_PSIZE(stf) / NBITS_BYTE / SZB_CHAR
+ call salloc (gpb, sz_gpb, TY_CHAR)
+
+ # Extract the binary value of each parameter in the GPB and encode it
+ # in FITS format in the IMIO user area.
+
+ offset = 0
+ for (pn=1; pn <= STF_PCOUNT(stf); pn=pn+1) {
+ pp = STF_PDES(stf,pn)
+ op = gpb + offset
+
+ # Fetch the value of the parameter from IMIO and write it into
+ # the GPB binary data structure.
+
+ switch (P_SPPTYPE(pp)) {
+ case TY_BOOL:
+ iferr (bval = imgetb (im, P_PTYPE(pp))) {
+ call erract (EA_WARN)
+ bval = false
+ }
+ # Memb[(op-1)/SZ_BOOL+1] = bval
+ if (SZ_INT != SZ_INT32) {
+ call i64to32 (bval, bval, 1)
+ call amovc (bval, Memc[op], SZ_INT32)
+ } else
+ call amovc (bval, Memc[op], SZ_BOOL)
+
+ # changed case for int to short and long
+ # to allow i*2 in gpb--dlb 11/3/87
+ case TY_SHORT:
+ iferr (sval = imgets (im, P_PTYPE(pp))) {
+ call erract (EA_WARN)
+ sval = 0
+ }
+ call amovc (sval, Memc[op], SZ_SHORT)
+
+ case TY_LONG:
+ iferr (lval = imgetl (im, P_PTYPE(pp))) {
+ call erract (EA_WARN)
+ lval = 0
+ }
+ if (SZ_INT != SZ_INT32) {
+ call i64to32 (lval, lval, 1)
+ call amovc (lval, Memc[op], SZ_INT32)
+ } else
+ call amovc (lval, Memc[op], SZ_LONG)
+
+ case TY_REAL:
+ iferr (rval = imgetr (im, P_PTYPE(pp))) {
+ # Currently with MWCS, WCS cards such as CRVAL, CDi_j,
+ # etc. (always type real or double) are omitted from the
+ # header if their value is zero. Hence if the card is
+ # missing assume a value of zero rather than issue a
+ # warning.
+
+ # call erract (EA_WARN)
+ rval = 0.0
+ }
+ # Memr[(op-1)/SZ_REAL+1] = rval
+ call amovc (rval, Memc[op], SZ_REAL)
+
+ case TY_DOUBLE:
+ iferr (dval = imgetd (im, P_PTYPE(pp))) {
+ # Skip warning as assume zero, as above or TY_REAL.
+ # call erract (EA_WARN)
+ dval = 0.0D0
+ }
+ # Memd[(op-1)/SZ_DOUBLE+1] = dval
+ call amovc (dval, Memc[op], SZ_DOUBLE)
+
+ case TY_CHAR:
+ # Blank fill the string buffer.
+ do i = 1, P_LEN(pp)
+ Memc[lbuf+i-1] = ' '
+
+ # Fetch the string value of the parameter.
+ iferr (call imgstr (im, P_PTYPE(pp), Memc[lbuf], SZ_LINE))
+ call erract (EA_WARN)
+
+ # Replace the EOS delimiter by a blank.
+ i = strlen (Memc[lbuf])
+ Memc[lbuf+i] = ' '
+
+ # Pack the blank filled array into the GPB.
+ call chrpak (Memc[lbuf], 1, Memc[gpb+offset], 1, P_LEN(pp))
+
+ default:
+ call error (1, badtype)
+ }
+
+ sz_param = P_PSIZE(pp) / NBITS_BYTE / SZB_CHAR
+ offset = offset + sz_param
+ }
+
+ # Write the GPB into the pixfile. The GPB is located at the very end
+ # of the data storage area for the group.
+
+ offset = (group * STF_SZGROUP(stf) + 1) - sz_gpb
+ call seek (pfd, offset)
+ iferr (call write (pfd, Memc[gpb], sz_gpb))
+ call error (5, writerr)
+
+ call sfree (sp)
+end