aboutsummaryrefslogtreecommitdiff
path: root/noao/mtlocal/cyber/rrcopy
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 /noao/mtlocal/cyber/rrcopy
downloadiraf-linux-fa080de7afc95aa1c19a6e6fc0e0708ced2eadc4.tar.gz
Initial commit
Diffstat (limited to 'noao/mtlocal/cyber/rrcopy')
-rw-r--r--noao/mtlocal/cyber/rrcopy/README2
-rw-r--r--noao/mtlocal/cyber/rrcopy/Revisions15
-rw-r--r--noao/mtlocal/cyber/rrcopy/mkpkg15
-rw-r--r--noao/mtlocal/cyber/rrcopy/rcrbits.x279
-rw-r--r--noao/mtlocal/cyber/rrcopy/rcrheader.x119
-rw-r--r--noao/mtlocal/cyber/rrcopy/rcrimage.x173
-rw-r--r--noao/mtlocal/cyber/rrcopy/rrcopy.h41
-rw-r--r--noao/mtlocal/cyber/rrcopy/rrcopy.x212
-rw-r--r--noao/mtlocal/cyber/rrcopy/semicode.doc310
-rw-r--r--noao/mtlocal/cyber/rrcopy/t_rrcopy.x147
10 files changed, 1313 insertions, 0 deletions
diff --git a/noao/mtlocal/cyber/rrcopy/README b/noao/mtlocal/cyber/rrcopy/README
new file mode 100644
index 00000000..ec7e7c70
--- /dev/null
+++ b/noao/mtlocal/cyber/rrcopy/README
@@ -0,0 +1,2 @@
+This directory contains source code for rrcopy, the Cyber RCOPY tape
+reader.
diff --git a/noao/mtlocal/cyber/rrcopy/Revisions b/noao/mtlocal/cyber/rrcopy/Revisions
new file mode 100644
index 00000000..09bf9e12
--- /dev/null
+++ b/noao/mtlocal/cyber/rrcopy/Revisions
@@ -0,0 +1,15 @@
+.help revisions Jun88 noao.mtlocal.cyber.rrcopy
+.nf
+noao$mtlocal/cyber/rrcopy/t_rrcopy.x, rcrheader.x
+ Fixed two places in t_rrcopy where the procedure was returning
+ without closing the mt file. Procedure rc_read_header was
+ not returning the value (OK) when NOT at EOF. These two errors,
+ while present all along, had not been seen until rrcopy was modified
+ to read tapes with more then one datafile; see below. (4-AUG-88 ShJ)
+
+noao$mtlocal/cyber/rrcopy/t_rrcopy.x
+ Added a hidden parameter "datafile" to the rrcopy task. This
+ allows more than one file of rcopy format data per tape. With
+ this "extension" to the rcopy format, many rcopy files can be
+ archived on a single tape. (26-JULY-88 ShJ)
+.endhelp
diff --git a/noao/mtlocal/cyber/rrcopy/mkpkg b/noao/mtlocal/cyber/rrcopy/mkpkg
new file mode 100644
index 00000000..6d2d99d3
--- /dev/null
+++ b/noao/mtlocal/cyber/rrcopy/mkpkg
@@ -0,0 +1,15 @@
+# The Cyber rcopy format reader RRCOPY makes the following contributions
+# to the dataio package library:
+
+$checkout libpkg.a ../../
+$update libpkg.a
+$checkin libpkg.a ../../
+$exit
+
+libpkg.a:
+ rcrbits.x ../pow.inc <error.h> <imhdr.h> <mach.h> rrcopy.h
+ rcrheader.x <error.h> <imhdr.h> <mach.h> rrcopy.h
+ rcrimage.x rrcopy.h <error.h> <imhdr.h> <mach.h>
+ rrcopy.x <mach.h> rrcopy.h
+ t_rrcopy.x rrcopy.h <error.h> <imhdr.h> <mach.h>
+ ;
diff --git a/noao/mtlocal/cyber/rrcopy/rcrbits.x b/noao/mtlocal/cyber/rrcopy/rcrbits.x
new file mode 100644
index 00000000..c6525787
--- /dev/null
+++ b/noao/mtlocal/cyber/rrcopy/rcrbits.x
@@ -0,0 +1,279 @@
+include <mach.h>
+include <imhdr.h>
+include <error.h>
+include "rrcopy.h"
+
+# RC_UP_12 -- Unpack 12-bit unsigned integers from a stream of bits.
+# Each output integer word contains successive 12-bit increments
+# of the input bit stream in the least significant bit positions.
+# It is assummed that the initial_bit_offset is the first bit of a
+# Cyber 60-bit word containing 5 packed 12-bit pixels, the first pixel
+# in the highest 12 bits.
+
+procedure rc_up_12 (input, initial_bit_offset, output, npix_unpk)
+
+char input[ARB]
+int output[npix_unpk], npix_unpk
+int initial_bit_offset, nbits, n, nn, bit_offset
+int npix_word, ncyb_words, index
+int bitupk()
+
+begin
+ nbits = 12
+ npix_word = 5
+ if (mod (npix_unpk, npix_word) == 0)
+ ncyb_words = (npix_unpk) / npix_word
+ else
+ call error (0, "Incorrect number of pixels to be unpacked")
+ index = 1
+
+ do n = 1, ncyb_words {
+ bit_offset = initial_bit_offset + (n * 60)
+ do nn = 1, npix_word {
+ bit_offset = bit_offset - nbits
+ output[index] = bitupk (input, bit_offset, nbits)
+ if (output[index] == 7777B)
+ output[index] = BLANK
+ index = index + 1
+ }
+ }
+end
+
+
+# RC_UP_20 -- Unpack 20-bit signed integers from a stream of bits.
+# Each output integer word contains sucessive 20-bit increments of the input.
+# Conversion from one's complement to two's complement is performed.
+# It is assummed that initial_bit_offset is the first bit of a Cyber
+# 60-bit word containing 3 packed 20-bit pixels, the first pixel in the
+# highest 20 bits.
+
+procedure rc_up_20 (input, initial_bit_offset, output, npix_unpk)
+
+char input[ARB]
+int output[npix_unpk], npix_unpk
+int nbits, n, index, bit_offset, initial_bit_offset
+int npix_word, ncyb_words, nn, pix_val
+int bitupk()
+
+begin
+ nbits = 20
+ npix_word = 3
+ if (mod (npix_unpk, npix_word) == 0)
+ ncyb_words = npix_unpk / npix_word
+ else
+ call error (0, "Incorrect number of pixels to be unpacked")
+ index = 1
+
+ do n = 1, ncyb_words {
+ bit_offset = initial_bit_offset + (n * 60)
+ do nn = 1, npix_word {
+ bit_offset = bit_offset - nbits
+ pix_val = bitupk (input, bit_offset, nbits)
+ if (pix_val == 3777777B)
+ pix_val = BLANK
+ else if (and (pix_val, 2000000B) != 0)
+ # negative pixel
+ pix_val = -and (3777777B, not(pix_val))
+ output[index] = pix_val
+ index = index + 1
+ }
+ }
+end
+
+
+# RC_UP_30 -- unpack Cyber 30-bit floating point numbers from a stream of
+# bits. The input bit stream is unpacked in 30-bit increments into
+# an integer array. Procedure REPACK_FP is called to reconstruct the
+# floating point numbers from this array. It is assumed initial_bit_offset
+# is the first bit of a Cyber 60-bit word containing 2 30-bit pixels, the
+# first pixel in the higher 30 bits.
+
+procedure rc_up_30 (input, initial_bit_offset, fp_value, npix)
+
+char input[ARB]
+real fp_value[npix]
+pointer int_buf, sp
+int initial_bit_offset, npix, bit_offset
+int nbits, n
+int bitupk()
+
+begin
+ # Allocate buffer space, allowing for maximum of 1 extraneous pixel
+ call smark (sp)
+ call salloc (int_buf, npix + 1, TY_INT)
+
+ nbits = 30
+ bit_offset = initial_bit_offset - 60
+
+ do n = 1, npix, 2 {
+ bit_offset = bit_offset + 90
+ Memi[int_buf + n - 1] = bitupk (input, bit_offset, 30)
+ bit_offset = bit_offset - nbits
+ Memi[int_buf + n] = bitupk (input, bit_offset, 30)
+ }
+
+ call rc_repack_fp (Memi[int_buf], fp_value, npix)
+ call sfree (sp)
+end
+
+
+# RC_UP_60R -- Unpack Cyber 60-bit floating point numbers from a stream
+# of bits. The 30 most significant bits from each 60-bit word are
+# unpacked into an integer array. Procedure REPACK_FP is called to
+# reconstruct the floating point numbers from this array.
+# An 18-bit mantissa, 11-bit exponent and a sign bit are unpacked into
+# the lower 30 bits of each output word.
+
+procedure rc_up_60r (input, initial_bit_offset, fp_value, nwords)
+
+char input[ARB]
+real fp_value[nwords]
+int initial_bit_offset, nwords, bit_offset
+pointer int_buf, sp
+int n, nbits_unpk, nbits
+int bitupk()
+
+begin
+ # Allocate space on stack
+ call smark (sp)
+ call salloc (int_buf, nwords, TY_INT)
+
+ nbits = 60
+ nbits_unpk = 30
+ bit_offset = initial_bit_offset + 30
+
+ do n = 1, nwords {
+ Memi[int_buf + n - 1] = bitupk (input, bit_offset, nbits_unpk)
+ bit_offset = bit_offset + 60
+ }
+
+ call rc_repack_fp (Memi[int_buf], fp_value, nwords)
+ call sfree (sp)
+end
+
+
+# RC_UP_60I -- Unpack 60-bit integers from a stream of bits. Each element
+# of output contains only the lower 32 bits of each input word, as this
+# procedure is called only for getting NROWS, NCOLS and a few other small
+# positive integer values. (A 60-bit intger is not a valid IPPS pixel type.)
+
+procedure rc_up_60i (input, initial_bit_offset, output, nwords)
+
+char input[ARB]
+int output[nwords]
+int initial_bit_offset, nwords, bit_offset
+int n, nbits_unpk, nbits
+int bitupk()
+
+begin
+ nbits_unpk = NBITS_INT
+ nbits = 60
+ bit_offset = initial_bit_offset
+
+ do n = 1, nwords {
+ output[n] = bitupk (input, bit_offset, nbits_unpk)
+ bit_offset = bit_offset + 60
+ }
+end
+
+
+# RC_UP_ID -- Unpacks ID string from input bit stream. The IPPS ID string is
+# written in 7-bit ASCII, with eight characters per Cyber word. The lowest
+# 4 bits of each 60-bit word is unused. The highest 7 bits of the first Cyber
+# word in the bit stream contains the character count.
+
+procedure rc_up_id (input, output)
+
+char input[SZ_HEADER]
+char output[SZ_HEADER]
+int nbits, nchar_offset, id_offset, nchars, n
+int nchars_word, ncyb_words, nn, index
+int bitupk()
+
+begin
+ nbits = 7
+ nchar_offset = NBITS_CYBER_WORD - 6
+ nchars = bitupk (input, nchar_offset, nbits)
+ ncyb_words = (nchars + 7) / 8
+ index = 1
+
+ do n = 1, ncyb_words {
+ if (n == 1) {
+ nchars_word = 7
+ id_offset = nchar_offset - 7
+ } else {
+ nchars_word = 8
+ id_offset = (n * NBITS_CYBER_WORD) - 6
+ }
+ do nn = 1, nchars_word {
+ output[index] = bitupk (input, id_offset, nbits)
+ index = index + 1
+ id_offset = id_offset - 7
+ }
+ }
+ output[nchars+1] = EOS
+end
+
+
+# RC_REPACK_FP -- returns a floating point number as the function value.
+# The input to REPACK_FP is an integer containing a 30-bit Cyber floating
+# point number in the least significant bits. The exponent, mantissa
+# and two bits indicating the sign are extracted and used to reassemble
+# the floating point value. Cyber blanks and overflows are returned as BLANK.
+
+procedure rc_repack_fp (int_value, float_value, nvalues)
+
+int int_value[ARB], nvalues
+real float_value[nvalues]
+
+int i, pixel
+int exp, mantissa
+real tbl[255]
+int bitupk(), and(), not()
+include "../pow.inc"
+
+begin
+ do i=1, nvalues {
+ pixel = int_value[i]
+ # Check for blanks
+ if (pixel == 1777000000B) {
+ float_value[i] = BLANK
+ next
+ }
+
+ # Check "bit59" and complement all bits if it is set
+ if (and (pixel, 4000000000B) != 0) {
+ pixel = not (pixel)
+ mantissa = -and (pixel, 777777B)
+ } else
+ mantissa = and (pixel, 777777B)
+
+ # Extract and interpret exponent: remove Cyber bias of 2000B
+ # and convert to two's complement if negative number
+ exp = bitupk (pixel, 19, 11)
+ if (exp > 1777B)
+ # "bit58" is set, positive exponent
+ exp = exp - 2000B
+ else
+ # negative exponent
+ exp = exp - 1777B
+
+ # Reconstruct the floating point value: 30 is added to the
+ # exponent because only the top 18 bits of the 48-bit mantissa
+ # were extracted; the 129 is to register the data array index.
+ # float_value[i] = real(mantissa) * 2 ** (exp + 30)
+ # (tbl[1] = 2 ** -128) ==> (2 ** n = tbl[n + 129]).
+
+ exp = exp + 30 + 129
+ if (exp <= 0) {
+ #call eprintf (
+ #"RRCOPY_RPACK_FP: Exponent underflow in following record\n")
+ float_value[i] = 0.0
+ } else if (exp > 255) {
+ #call eprintf (
+ #"RRCOPY_REPACK_FP: Exponent overflow in following record\n")
+ float_value[i] = MAX_REAL
+ } else if (exp > 0 && exp <= 255)
+ float_value[i] = double (mantissa) * tbl[exp]
+ }
+end
diff --git a/noao/mtlocal/cyber/rrcopy/rcrheader.x b/noao/mtlocal/cyber/rrcopy/rcrheader.x
new file mode 100644
index 00000000..2187c6a1
--- /dev/null
+++ b/noao/mtlocal/cyber/rrcopy/rcrheader.x
@@ -0,0 +1,119 @@
+include <mach.h>
+include <imhdr.h>
+include <error.h>
+include "rrcopy.h"
+
+# RC_READ_HEADER -- reads the IPPS header (64 60-bit words) as
+# a bit stream into consecutive elements of char array header.
+# Any extraneous information between the header and data is skipped;
+# the tape is left positioned at the first data record.
+
+int procedure rc_header_read (rd, rp)
+
+int rd
+pointer rp
+char raw_header[SZ_HEADER], header[SZ_HEADER]
+int nchars_to_skip, first_word
+int rc_read_cyber()
+errchk rc_header_unpk, rc_skip_chars, rc_read_cyber, rc_order_cyber_bits
+
+begin
+ if (rc_read_cyber (rd, raw_header, SZ_HEADER) == EOF)
+ return (EOF)
+
+ first_word = 1
+ call rc_order_cyber_bits (raw_header, first_word, header, LEN_PRU)
+
+ # Unpack bit stream and fill structure rp
+ iferr {
+ call rc_header_unpk (header, rp)
+ nchars_to_skip = (PRU_ROW_ONE(rp) - 1) * NBITS_PRU / NBITS_CHAR
+ } then {
+ call erract (EA_WARN)
+ # Position to first row of raster before posting error
+ if (nchars_to_skip > 0)
+ call rc_skip_chars (rd, nchars_to_skip)
+ call error (1, "Bad header, attempting to skip raster")
+ }
+
+ # Position to first row of IPPS raster
+ if (nchars_to_skip > 0)
+ call rc_skip_chars (rd, nchars_to_skip)
+
+ return (OK)
+end
+
+
+# RC_LIST_HEADER -- prints the RCOPY header information.
+
+procedure rc_list_header (rp, raster_num)
+
+pointer rp
+int raster_num
+
+begin
+ # Print header information from rcopy tape
+ call printf ("[%d]%7t IPPS_ID: %s\n")
+ call pargi (raster_num)
+ call pargstr (IPPS_ID(rp))
+ call printf ("%7t NCOLS=%d, NROWS=%d, MIN=%g, MAX=%g, NBPP=%d\n")
+ call pargi (NCOLS(rp))
+ call pargi (NROWS(rp))
+ call pargr (DATA_MIN(rp))
+ call pargr (DATA_MAX(rp))
+ call pargi (BITS_PIXEL(rp))
+end
+
+
+# RC_UNPACK_HEADER -- unpacks header words from the char array header
+# and fills the RCOPY data structure. A few values are checked to
+# make sure a valid IPPS raster is being read. Offsets to various
+# header words have been defined previously.
+
+procedure rc_header_unpk (header, rp)
+
+char header[SZ_HEADER]
+pointer rp
+
+begin
+ # From the reordered array, first the ID is unpacked
+ call rc_up_id (header, IPPS_ID(rp))
+
+ # An EOR marker terminates each raster
+ call rc_up_60i (header, EOR_OFFSET, PRU_EOR(rp), 1)
+
+ # The PRU containing the first data row
+ call rc_up_60i (header, FIRST_PRU_OFFSET, PRU_ROW_ONE(rp), 1)
+
+ # Most significant 30 bits of the data min are used
+ call rc_up_60r (header, MIN_OFFSET, DATA_MIN(rp), 1)
+
+ # Most significant 30 bits of the data max are used
+ call rc_up_60r (header, MAX_OFFSET, DATA_MAX(rp), 1)
+
+ # Bits per pixel is unpacked and tested
+ call rc_up_60i (header, DATA_TYPE_OFFSET, BITS_PIXEL(rp), 1)
+
+ switch (BITS_PIXEL(rp)) {
+ case 12,20,30,60:
+ ;
+ default:
+ call error (2, "Incorrect IPPS BITS_PIXEL")
+ }
+
+ # Number of columns is unpacked and tested
+ call rc_up_60i (header, NCOLS_OFFSET, NCOLS(rp), 1)
+ if (NCOLS(rp) <= 0)
+ call error (2, "IPPS ncols <= 0")
+
+ # Number of Cyber words per row must be integral # of PRU's
+ call rc_up_60i (header, NWORDS_OFFSET, WRDS_PER_ROW(rp), 1)
+
+ if (mod (WRDS_PER_ROW(rp), LEN_PRU) != 0)
+ call error (2, "Invalid IPPS NWPR")
+
+ # Number of rows is unpacked and tested
+ call rc_up_60i (header, NROWS_OFFSET, NROWS(rp), 1)
+ if (NROWS(rp) <= 0)
+ call error (2, "IPPS nrows <= 0")
+end
diff --git a/noao/mtlocal/cyber/rrcopy/rcrimage.x b/noao/mtlocal/cyber/rrcopy/rcrimage.x
new file mode 100644
index 00000000..dc7ebcfb
--- /dev/null
+++ b/noao/mtlocal/cyber/rrcopy/rcrimage.x
@@ -0,0 +1,173 @@
+include <mach.h>
+include <imhdr.h>
+include <error.h>
+include "rrcopy.h"
+
+# RC_READ_IMAGE -- reads the rcopy image row by row from the tape and writes
+# the output image. At the completion of READ_IMAGE, the tape is positioned
+# to the header record of the next tape raster.
+
+procedure rc_read_image (rd, out_fname, data_type, rp)
+
+int rd, data_type
+char out_fname[SZ_FNAME]
+pointer rp
+
+pointer sp, im, cyber_buf, spp_buf
+int nchars_per_row, nbits_skip, nchars_to_skip, i
+long clktime()
+
+int rc_read_cyber()
+pointer immap(), impl2r()
+errchk rc_skip_chars, immap, rc_ipps_to_iraf
+
+begin
+ # Allocate buffer for rcopy image pixels
+ call smark (sp)
+ nchars_per_row = WRDS_PER_ROW(rp) * NBITS_CYBER_WORD / NBITS_CHAR
+ call salloc (cyber_buf, nchars_per_row, TY_CHAR)
+ call salloc (spp_buf, nchars_per_row, TY_CHAR)
+
+ # Map new iraf image and set up image header
+ im = immap (out_fname, NEW_IMAGE, 0)
+ IM_LEN(im, 1) = NCOLS(rp)
+ IM_LEN(im, 2) = NROWS(rp)
+ call strcpy (IPPS_ID(rp), IM_TITLE(im), SZ_IMTITLE)
+ IM_MIN(im) = DATA_MIN(rp)
+ IM_MAX(im) = DATA_MAX(rp)
+
+ # Set optimum image pixel type
+ if (data_type == NOT_SET) {
+ switch (BITS_PIXEL(rp)) {
+ case 12:
+ IM_PIXTYPE(im) = TY_SHORT
+ case 20:
+ IM_PIXTYPE(im) = TY_REAL
+ case 30:
+ IM_PIXTYPE(im) = TY_REAL
+ case 60:
+ IM_PIXTYPE(im) = TY_REAL
+ default:
+ call error (3, "IPPS BITS_PIXEL is incorrect")
+ }
+ } else
+ IM_PIXTYPE(im) = data_type
+ IM_LIMTIME(im) = clktime (long(0))
+
+ # Loop over rows to read, reorder and convert pixels.
+ for (i=1; i <= NROWS(rp); i=i+1) {
+ if (rc_read_cyber (rd, Memc[cyber_buf], nchars_per_row) == EOF)
+ call error (4, "Unexpected EOT when reading image")
+ call rc_order_cyber_bits (Memc[cyber_buf], 1, Memc[spp_buf],
+ WRDS_PER_ROW(rp))
+ call rc_ipps_to_iraf (Memc[spp_buf], Memr[impl2r(im,i)], NCOLS(rp),
+ BITS_PIXEL(rp))
+ }
+
+ # Skip from present position to end of rcopy raster
+ nbits_skip = ((PRU_EOR(rp) - PRU_ROW_ONE(rp)) * LEN_PRU -
+ (WRDS_PER_ROW(rp) * NROWS(rp))) * NBITS_CYBER_WORD + NBITS_EOR_MARK
+
+ nchars_to_skip = nbits_skip / NBITS_CHAR
+ call rc_skip_chars (rd, nchars_to_skip)
+
+ call imunmap (im)
+ call sfree (sp)
+end
+
+
+# RC_IPPS_TO_IRAF -- performs the conversion from Cyber pixels to IRAF pixels.
+# Each row of the rcopy image is required to occupy an integral of Cyber
+# PRU's, so the input buffer contains pixels plus filler. The entire
+# buffer is converted and npix pixels are written to the output image.
+
+procedure rc_ipps_to_iraf (in_buf, iraf_real, npix, nbits_pixel)
+
+char in_buf[ARB]
+real iraf_real[npix]
+pointer iraf_int, sp
+int nbits_pixel, npix, bit_offset, npix_unpk, npix_cyber_wrd
+errchk rc_up_12, rc_up_20
+
+begin
+ # Calculate and allocate (maximum) space needed on the stack. The
+ # number of pixels unpacked will always fill an integral number
+ # of Cyber words. A maximum of 4 extraneous pixels will be unpacked.
+ call smark (sp)
+ call salloc (iraf_int, npix + 4, TY_INT)
+ bit_offset = 1
+
+ switch (nbits_pixel) {
+ case 12:
+ npix_cyber_wrd = 5
+ npix_unpk = ((npix + 4) / npix_cyber_wrd) * npix_cyber_wrd
+ call rc_up_12 (in_buf, bit_offset, Memi[iraf_int], npix_unpk)
+ call achtir (Memi[iraf_int], iraf_real, npix)
+
+ case 20:
+ npix_cyber_wrd = 3
+ npix_unpk = ((npix + 2) / npix_cyber_wrd) * npix_cyber_wrd
+ call rc_up_20 (in_buf, bit_offset, Memi[iraf_int], npix_unpk)
+ call achtir (Memi[iraf_int], iraf_real, npix)
+
+ case 30:
+ call rc_up_30 (in_buf, bit_offset, iraf_real, npix)
+
+ case 60:
+ call rc_up_60r (in_buf, bit_offset, iraf_real, npix)
+
+ default:
+ call error (5, "Illegal IPPS #B/P")
+ }
+
+ call sfree (sp)
+end
+
+
+# RC_SKIP_IMAGE -- skips over an RCOPY raster once the header has been
+# read. When SKIP_IMAGE returns, the tape is positioned to the first
+# record of the next tape image.
+
+procedure rc_skip_image (rd, rp)
+
+int rd
+pointer rp
+int nchars_to_skip
+errchk rc_skip_chars
+
+begin
+ # Calculate number of chars in image
+ nchars_to_skip = ((PRU_EOR(rp) - PRU_ROW_ONE(rp)) *
+ LEN_PRU * NBITS_CYBER_WORD + NBITS_EOR_MARK ) / NBITS_CHAR
+ call rc_skip_chars (rd, nchars_to_skip)
+end
+
+# RC_SKIP_CHARS -- positions the tape by skipping the requested number of chars.
+
+procedure rc_skip_chars (rd, nchars_to_skip)
+
+int rd, nchars_to_skip
+pointer sp, dummy
+int nblks_read, nchars_remaining, i
+int rc_read_cyber()
+
+begin
+ call smark (sp)
+ call salloc (dummy, SZ_TAPE_BLK, TY_CHAR)
+
+ # Calculate the number of full blocks to skip
+ nblks_read = nchars_to_skip / SZ_TAPE_BLK
+ nchars_remaining = mod (nchars_to_skip, SZ_TAPE_BLK)
+
+ # Read from tape, a block at a time
+ for (i=1; i <= nblks_read; i=i+1) {
+ if (rc_read_cyber (rd, Memc[dummy], SZ_TAPE_BLK) == EOF)
+ call error (6, "Unexpected EOT when skipping image")
+ }
+
+ # Read partial block from tape
+ if (rc_read_cyber (rd, Memc[dummy], nchars_remaining) == EOF)
+ call error (7, "Unexpected EOT when skipping image")
+
+ call sfree (sp)
+end
diff --git a/noao/mtlocal/cyber/rrcopy/rrcopy.h b/noao/mtlocal/cyber/rrcopy/rrcopy.h
new file mode 100644
index 00000000..9579b623
--- /dev/null
+++ b/noao/mtlocal/cyber/rrcopy/rrcopy.h
@@ -0,0 +1,41 @@
+
+# Definitions for the Cyber RCOPY tape reader
+
+define NBITS_CHAR (NBITS_BYTE * SZB_CHAR) # Number of bits per char
+define NBITS_CYBER_WORD 60 # Number of bits per Cyber word
+define LEN_PRU 64 # Number of words per Cyber pru
+define NBITS_PRU 3840 # Number of bits per Cyber pru
+define NCHARS_NOISE (48 / NBITS_CHAR) # Nchars in a Cyber noise record
+define NBITS_EOR_MARK 48 # Number of bits per eor marker
+define SZ_HEADER ((64 * 60) / NBITS_CHAR) # Size in chars of IPPS header
+define SZ_TAPE_BLK ((512 * 60) / NBITS_CHAR) # Size in chars of tape block
+define SZ_BUFFER (SZ_TAPE_BLK + 100) # Size of tape buffer for read
+define SZ_IPPS_ID 127 # Max number of characters in ID
+define MAX_RANGES 100
+define NOT_SET 0 # Flag for data_type not set
+define BLANK 0.0 # Temporary value for blanks
+
+# Bit-offsets to IPPS header words
+
+define DATA_TYPE_OFFSET (16 * 60 + 1) # Offset to data_type (nbpp)
+define NCOLS_OFFSET (17 * 60 + 1) # Offset to ncols (nppr)
+define NWORDS_OFFSET (18 * 60 + 1) # Offet to nwords_per_row
+define NROWS_OFFSET (20 * 60 + 1) # Offset to nrows
+define FIRST_PRU_OFFSET (21 * 60 + 1) # Offset to 1st pru of raster
+define MIN_OFFSET (31 * 60 + 1) # Offset to data min
+define MAX_OFFSET (32 * 60 + 1) # Offset to data max
+define EOR_OFFSET (44 * 60 + 1) # Offset to terminating pru
+
+# The IPPS raster descriptor structure RP:
+
+define LEN_RP 10 + SZ_IPPS_ID + 1
+
+define BITS_PIXEL Memi[$1]
+define PRU_EOR Memi[$1+1]
+define WRDS_PER_ROW Memi[$1+2]
+define PRU_ROW_ONE Memi[$1+3]
+define NCOLS Memi[$1+4]
+define NROWS Memi[$1+5]
+define DATA_MIN Memr[P2R($1+6)]
+define DATA_MAX Memr[P2R($1+7)]
+define IPPS_ID Memc[P2C($1+10)]
diff --git a/noao/mtlocal/cyber/rrcopy/rrcopy.x b/noao/mtlocal/cyber/rrcopy/rrcopy.x
new file mode 100644
index 00000000..0a6b5de7
--- /dev/null
+++ b/noao/mtlocal/cyber/rrcopy/rrcopy.x
@@ -0,0 +1,212 @@
+include <mach.h>
+include "rrcopy.h"
+
+.help rc_read_cyber
+.nf ________________________________________________________________________
+RC_READ_CYBER -- Read binary chars from a file, ignoring short "noise" records.
+Data is read in chunks from the file buffer passed as a bit stream into the
+output buffer. (See also: read_dumpf and get_cyber_words.) The
+file buffer is refilled as necessary by calling READ; the output buffer is
+supplied by the calling procedure. Cyber noise records (48 bits)
+are not transferred to the output buffer and so are ignored. READ_CYBER_INIT
+must be called to initialize variables for CYBER_READ. Variables marking the
+current position and top of the buffer are initialized.
+.endhelp ___________________________________________________________________
+
+int procedure rc_read_cyber (rd, out_buffer, maxch)
+
+int buf_pos, buf_top
+int rd, maxch
+char out_buffer[ARB]
+char block_buf[SZ_BUFFER]
+int nchars, chunk_size, nchars_read
+int read(), rc_read_cyber_init()
+
+begin
+ for (nchars = 0; nchars < maxch; nchars = nchars + chunk_size) {
+ # See if it is necessary to transfer more data from the binary file
+ # to the file buffer. This will be necessary when all data from the
+ # file buffer has been moved to the output buffer.
+
+ if (buf_pos >= buf_top) {
+ # Read the next non-noise record into block_buf; reset buf_pos
+ repeat {
+ nchars_read = read (rd, block_buf, SZ_BUFFER)
+ } until (nchars_read >= NCHARS_NOISE || nchars_read == EOF)
+ buf_pos = 1
+ buf_top = nchars_read
+ }
+
+ # The number of chars to output is the smaller of the number of
+ # characters requested or the number of characters left in the
+ # buffer
+
+ if (nchars_read == EOF)
+ break
+ else
+ chunk_size = min (maxch - nchars, buf_top - buf_pos + 1)
+
+ # Move data to output array, increment buffer offset
+ call amovc (block_buf[buf_pos], out_buffer[nchars+1], chunk_size)
+ buf_pos = buf_pos + chunk_size
+ }
+
+ if (nchars == 0)
+ return (EOF)
+ else
+ return (nchars)
+
+entry rc_read_cyber_init ()
+
+ buf_pos = 1
+ buf_top = 0
+ return (OK)
+end
+
+
+.help rc_order_cyber_bits
+.nf __________________________________________________________________________
+RC_ORDER_CYBER_BITS -- Convert raw data array from a 60-bit Cyber computer into
+an SPP bit-array. The output SPP bit-array is a bit-packed array of 60-bit
+Cyber words, i.e., bits 1-60 are word 1, bits 61-120 are word 2, and so on.
+The least significant Cyber bit is bit 1 in each output word and the most
+significant bit is bit 60. [MACHDEP].
+
+When the Cyber outputs an array of 60 bit Cyber words it moves a stream of
+bits into output bytes, filling however many bytes as necessary to output a
+given number of Cyber words. The most significant bits are output first,
+i.e., bit 60 of the first word is moved to bit 8 of the first output byte,
+bit 59 is moved to bit 7 of the first output byte, and so on. If effect the
+Cyber byte flips each 60-bit word.
+
+To deal with Cyber words as an ordered bit stream we must reorder the bytes
+and bits so that the least significant bits are first. This function is
+performed by the primitives CYBOOW and CYBOEW (order odd/even Cyber word)
+for individual 60-bit Cyber words. A portable (and less efficient) version
+of order_cyber_bits is available which does not use these primitives.
+.endhelp _____________________________________________________________________
+
+
+procedure rc_order_cyber_bits (raw_cyber, first_cyber_word, bit_array,
+ ncyber_words)
+
+char raw_cyber[ARB] # raw Cyber array (e.g. from tape)
+int first_cyber_word # first 60-bit Cyber word to be unpacked
+char bit_array[ARB] # output bit-array
+int ncyber_words # number of Cyber words to unpack
+
+bool odd_word
+int word, inbit, outbit
+
+begin
+ odd_word = (mod (first_cyber_word, 2) == 1)
+ inbit = (first_cyber_word - 1) * NBITS_CYBER_WORD + 1
+ outbit = 1
+
+ do word = 1, ncyber_words {
+ # Call odd or even primitive to reorder bits and move 60-bit
+ # ordered Cyber word to the output array.
+
+ if (odd_word) {
+ call cyboow (raw_cyber, inbit, bit_array, outbit)
+ odd_word = false
+ } else {
+ call cyboew (raw_cyber, inbit, bit_array, outbit)
+ odd_word = true
+ }
+
+ inbit = inbit + NBITS_CYBER_WORD
+ outbit = outbit + NBITS_CYBER_WORD
+ }
+end
+
+
+# The portable version of order_cyber_bits follows.
+#.help order_cyber_bits
+#.nf __________________________________________________________________________
+#ORDER_CYBER_BITS -- Convert a raw data array from a 60-bit Cyber computer into
+#an SPP bit-array. The output SPP bit-array is a bit-packed array of 60-bit
+#Cyber words, i.e., bits 1-60 are word 1, bits 61-120 are word 2, and so on.
+#The least significant Cyber bit is bit 1 in each output word and the most
+#significant bit is bit 60. [MACHDEP].
+#
+#The byte stream from the Cyber contains bits 53-60 of the first word in the
+#first byte, bits 45-52 in the second byte, and so on (most significant bytes
+#first). In essence we swap the order of the 7 8-bit bytes and the 4-bit half
+#byte in each 60 bit word. The bits in each byte are in the correct order.
+#
+#Each successive pair of Cyber words fits into 15 bytes. Byte 8 contains the
+#last 4 bits of word 1 in the most signficant half of the byte and the first
+#4 bits of word 2 in the first half of the byte. In each 60 bit word we must
+#move bit segments (bytes or half bytes) as follows (for the VAX):
+#
+#Odd words (from N*60 bit-offset):
+# [from] [to] [nbits]
+# 1 53 8
+# 9 45 8
+# 17 37 8
+# 25 29 8
+# 33 21 8
+# 41 13 8
+# 49 5 8
+# 61 1 4
+#
+#Even words (from N*60 bit-offset):
+# [from] [to] [nbits]
+# -3 57 4
+# 5 49 8
+# 13 41 8
+# 21 33 8
+# 29 25 8
+# 37 17 8
+# 45 9 8
+# 53 1 8
+#.endhelp _____________________________________________________________________
+#
+#define NBITS_PER_WORD 60
+#define NSEGMENTS 8
+#
+#
+#procedure order_cyber_bits (raw_cyber, first_cyber_word, bit_array,
+# ncyber_words)
+#
+#char raw_cyber[ARB] # raw Cyber array (e.g. from tape)
+#int first_cyber_word # first 60-bit Cyber word to be unpacked
+#char bit_array[ARB] # output bit-array
+#int ncyber_words # number of Cyber words to unpack
+#
+#int word, inword, inbit, outbit, temp, i
+#int o_from[NSEGMENTS], o_to[NSEGMENTS], o_nbits[NSEGMENTS]
+#int e_from[NSEGMENTS], e_to[NSEGMENTS], e_nbits[NSEGMENTS]
+#int bitupk()
+#
+#data o_from / 1, 9,17,25,33,41,49,61/ # odd words
+#data o_to /53,45,37,29,21,13, 5, 1/
+#data o_nbits / 8, 8, 8, 8, 8, 8, 8, 4/
+#data e_from /-3, 5,13,21,29,37,45,53/ # even words
+#data e_to /57,49,41,33,25,17, 9, 1/
+#data e_nbits / 4, 8, 8, 8, 8, 8, 8, 8/
+#
+#begin
+# do word = 1, ncyber_words {
+# inword = first_cyber_word + word - 1
+# inbit = (inword - 1) * NBITS_PER_WORD
+# outbit = ( word - 1) * NBITS_PER_WORD
+#
+# # Move bits to the output bit array. Segment list used depends
+# # on whether the word is an odd or even word. This code will work
+# # even if the caller only wishes to order a single word.
+#
+# if (mod (inword,2) == 1) {
+# do i = 1, NSEGMENTS {
+# temp = bitupk (raw_cyber, inbit + o_from[i], o_nbits[i])
+# call bitpak (temp, bit_array, outbit + o_to[i], o_nbits[i])
+# }
+# } else {
+# do i = 1, NSEGMENTS {
+# temp = bitupk (raw_cyber, inbit + e_from[i], e_nbits[i])
+# call bitpak (temp, bit_array, outbit + e_to[i], e_nbits[i])
+# }
+# }
+# }
+#end
diff --git a/noao/mtlocal/cyber/rrcopy/semicode.doc b/noao/mtlocal/cyber/rrcopy/semicode.doc
new file mode 100644
index 00000000..a7ad514c
--- /dev/null
+++ b/noao/mtlocal/cyber/rrcopy/semicode.doc
@@ -0,0 +1,310 @@
+Semicode for Cyber RCOPY Reader; Frozen at "detailed semicode" stage, Jan 84.
+
+
+# rcopy tape descriptor
+
+struct rcopy {
+
+ real data_min # minimum data value
+ real data_max # maximum data value
+ int nrows # number of rows in ipps raster
+ int ncols # number of columns in ipps raster
+ int data_type # number of bits per pixel in the ipps raster
+ int pru_eor # pru position of level zero eor
+ int wrds_per_row # number of 60-bit words per row; each row
+ # occupies an integral number of 64word pru's.
+ int pru_row_one # relative pru ordinal of the first row of raster.
+ char ipps_id # id string of the ipps raster
+}
+
+procedure t_rrcopy (rcopy_file, raster_list, iraf_file)
+
+
+begin
+ # get input filename and open tape drive
+ rcopy_fd = open (rcopy_file)
+
+ # get output filename if it will be needed
+ if (make_image = yes)
+ outfile = fetch root name of output file
+
+ # expand list of rasters to be read from tape
+ if (decode_ranges (raster_list, range, MAX_RANGES, nfiles) == ERR)
+ call error (0, "Illegal raster number list")
+
+ raster_number = 0
+ tape_pos = 1
+ while (get_next_number (range, raster_number, != EOF) {
+ # position tape to first record of raster_number
+ if (tape_pos != raster_number) {
+ iferr {
+ stat = position_rcopy (rcopy_fd, tape_pos ,raster_number)
+ if (stat = EOF)
+ return
+ } then
+ call ERRACT (EA_FATAL)
+ }
+ iraffile = generate output filename from root
+ iferr {
+ (stat = read_rcopy(rcopy_fd, iraffile, tape_pos))
+ if (stat = EOF)
+ return
+ } then {
+ call ERRACT (EA_WARN)
+ skip over rcopy raster
+ }
+ }
+
+end
+
+int procedure position_rcopy (rcopy_fd, tape_pos, raster_number)
+
+begin
+
+ nrasters_skip = raster_number - tape_pos
+ for (i=1; i<=nrasters_skip; i=i+1) {
+ stat = read_header (rcopy_fd, rcopy)
+ if (stat = EOF)
+ return (EOF)
+ call read_header (rcopy_fd, rcopy)
+ call skip_image (rcopy_fd, rcopy)
+ }
+end
+
+int procedure read_rcopy (rcopy_fd, iraffile, tape_pos)
+
+begin
+
+ # Read ipps raster header from rcopy tape
+ stat = read_header (rcopy_fd, rcopy)
+ if (stat = EOF)
+ return (EOF)
+
+ # Print header information from rcopy tape
+ if (print_header)
+ call print_header (rcopy)
+
+ # read image data if desired
+ if (make_image)
+ call read_image(rcopy_fd, iraffile, rcopy)
+
+ # skip image if not to be read
+ else
+ call skip_image (rcopy_fd, rcopy)
+
+ # increment tape position marker
+ tape_pos = tape_pos + 1
+
+
+end
+
+int procedure read_header(rcopy_fd, rcopy)
+
+begin
+ # structure rcopy contains decoded header
+ # Read ipps header (64 60-bit words = 240 chars) as a
+ # bit stream into temp.
+ NBITS_CHAR = SZB_CHAR * NBITS_BYTE
+ NBITS_CYBER_WORD = 60
+ NWORDS_CYBER_PRU = 64
+ SZ_HEADER = 240
+ stat = read_tape (rcopy_fd, raw_header, SZ_HEADER)
+ if (stat = EOF))
+ return (EOF)
+
+ # Unpack bit stream and fill structure rcopy
+ call unpack_header (raw_header, rcopy)
+
+ # skip to first row of raster
+ if (rcopy.pru_row_one not equal to 1) {
+ nchars_to_skip = (rcopy.pru_row_one - 1) * NWORDS_CYBER_PRU
+ * NBITS_CYBER_WORD / NBITS_CHAR
+ call skip_chars (rcopy_fd, nchars_to_skip)
+ }
+end
+
+procedure read_image (rcopy_fd, iraffile, rcopy)
+
+begin
+
+ # map new iraf image and set up image header
+ im = immap (iraffile, NEW_IMAGE)
+ im.im_len[1] = rcopy.ncols
+ im.im_len[2] = rcopy.nrows
+ im.im_title = rcopy.ipps_id
+ im.im_min = rcopy.data_min
+ im.im_max = rcopy.data_max
+
+ if (user hasn's supplied data type) {
+ switch (rcopy.data_type) {
+ case 12 :
+ im.im_pixtype = short
+ case 20 :
+ im.im_pixtype = real
+ case 30 :
+ im.im_pixtype = real
+ default:
+ call error (0, "error in data_type")
+ }
+ }
+
+ # Calculate number of chars per row; this will always be an
+ # integral number of chars because rcopy.words_per_row
+ # is always divisible by 64.
+ NBITS_CHAR = SZB_CHAR * NBITS_BYTE
+ NBITS_CYBER_WORD = 60
+ NWORDS_CYBER_PRU = 64
+ num_chars_per_row = rcopy.wrds_per_row * NBITS_CYBER_WORD / NBITS_CHAR
+
+ # Loop to read rcopy raster line by line into buf1, then
+ # convert ipps pixels to iraf pixels.
+ for(i=1; i<=rcopy.nrows; i=i+1) {
+ stat = read a single row from the internal buffer
+ if (stat = EOF) {
+ close imagefile already accumulated
+ call error (0, "unexpected EOF at row# ")
+ }
+ call ipps_to_iraf (buf1, Memr[impl2r(im,i)], rcopy)
+ }
+
+ # Read until header of next raster into dummy buffer.
+ # Calculate offset in chars from present position to eor
+ nchars_to_skip = (((rcopy.eor - rcopy.pru_row_one) * NWORDS_CYBER_PRU
+ + (rcopy.words_per_row * rcopy.nrows)) * NBITS_CYBER_WORD + 48)
+ / NBITS_CHAR
+
+ call skip_chars (rcopy_fd, nchars_to_skip)
+end
+
+procedure ipps_to_iraf (buf1, buf2, rcopy)
+
+begin
+
+ # convert (rcopy.ncols * rcopy.data_type ) bits from buf1.
+ # This is the number of bits per row that actually represent
+ # pixels. buf1 contains pixels plus filler.
+
+ switch (rcopy.data_type) {
+ case 12:
+ call unpack12 (buf1, bit_offset, buf2, npix)
+ case 20:
+ call unpack20 (buf1, bit_offset, buf2, npix)
+ case 30:
+ call unpack30 (buf1, bit_offset, buf2, npix)
+ default:
+ call error (0, "illegal ipps #b/p")
+ }
+end
+
+procedure skip_image(rcopy_fd, rcopy)
+
+begin
+
+ # Calculate number of chars in image
+ nchars_to_skip = ((rcopy.eor - rcopy.pru_row_one ) * NWORDS_CYBER_PRU *
+ NBITS_CYBER_WORD + 48 ) / NBITS_CHAR
+ call skip_chars (rcopy_fd, nchars_to_skip)
+
+end
+
+procedure print_header (rcopy)
+
+begin
+ # print header information from rcopy tape
+ print, rcopy.ipps_id, rcopy.ncols, rcopy.nrows, rcopy.data_min,
+ rcopy.data_max, rcopy.ipps_data_type
+end
+
+procedure unpack_header (raw_header, rcopy)
+
+begin
+
+ get from raw_header: nrows, ncols, data_type, ipps_id, pru_eor,
+ wrds_per_row, pru_row_one, data_min, data_max
+
+ if (rcopy.data_type != 12, 20, or 30)
+ call error (0, "invalid ipps #b/p")
+ if (nrows or ncols or pru_row_one !> 0)
+ call error (0, "invalid ipps raster")
+ if (wrds_per_row not divisible by 64)
+ call error (0, "invalid ipps raster")
+
+end
+
+procedure skip_chars (rcopy_fd, nchars_to_skip)
+
+begin
+
+ # calculate the number of chars in a tape block = (512 * 60) / 16
+ # This is the number of chars to be read at one time.
+ SZ_TAPE_BLK = 1920
+
+ # calculate number of blocks to skip (type int)
+ nblks_read = nchars_to_skip / SZ_TAPE_BLK
+ nchars_remaining = mod (nchars_to_skip, SZ_TAPE_BLK)
+
+ # read chars into dummy buffer
+ for (i=1; i<=nblks_read; i=i+1)
+ stat = read_tape (rcopy_fd, dummy, SZ_TAPE_BLK)
+
+ stat = read_tape (rcopy_fd, dummy, nchars_remaining)
+
+ # confirm reaching eor
+ if (searching for eor) {
+ reread last 3 chars and compare with level zero eor marker
+ if (eor not confirmed)
+ call error (0, "attempted skip to eor unsuccessful")
+ }
+
+end
+
+
+.help rrcopy 2 "Program Structure"
+.sh
+RCOPY Structure Chart
+
+.nf
+procedure t_rrcopy ()
+# Returns when file list is satisfied or if EOT is encountered
+
+ int procedure read_header (rcopy_fd, rcopy)
+ #returns EOF, ERR or OK
+
+ int procedure read (rcopy_fd, raw_header, SZ_HEADER)
+ #returns EOF or OK
+
+ int procedure unpack_header (raw_header, rcopy)
+ #returns ERR or OK
+
+ int procedure skip_image (rcopy_fd, rcopy)
+ #returns ERR, EOF or OK
+
+ int procedure skip_chars (rcopy_fd, nchars_to_skip)
+ #returns EOF, ERR or OK
+
+ procedure read_rcopy (rcopy_fd, iraffile)
+ #aborts if output filename exists and noclobber is set
+
+ int procedure read_header (rcopy_fd, rcopy)
+ #returns EOF, ERR or OK
+
+ int procedure read (rcopy_fd, raw_header, SZ_HEADER)
+ #returns EOF or OK
+
+ int procedure unpack_header (raw_header, rcopy)
+ #returns ERR or OK
+
+ procedure print_header (rcopy)
+
+ procedure read_image (rcopy_rd, iraffile, rcopy)
+ #returns EOF, or OK
+
+ int procedure read (rcopy_rd, buf1, num_chars_per_row)
+ #returns EOF or OK
+
+ int procedure ipps_to_iraf
+ #returns ERR or OK
+
+ int procedure skip_image (rcopy_rd, rcopy)
+ #returns EOF, ERR or OK
+.endhelp
diff --git a/noao/mtlocal/cyber/rrcopy/t_rrcopy.x b/noao/mtlocal/cyber/rrcopy/t_rrcopy.x
new file mode 100644
index 00000000..9bb83885
--- /dev/null
+++ b/noao/mtlocal/cyber/rrcopy/t_rrcopy.x
@@ -0,0 +1,147 @@
+include <mach.h>
+include <imhdr.h>
+include <error.h>
+include "rrcopy.h"
+
+# T_RRCOPY -- The main procedure for the RCOPY reader. The RCOPY reader
+# converts IPPS rasters written in RCOPY format to IRAF images. All IPPS
+# rasters on an RCOPY tape are in a single file. Each raster header must
+# be read before the image can be either skipped or read. T_RRCOPY gets
+# parameters from the cl and decodes the string of rasters to be read. It
+# then calls READ_HEADER for each raster on the tape. The header information
+# is printed if print_header=true. If make_image = true, the image is
+# converted to an IRAF image by READ_IMAGE. Otherwise, the image is skipped
+# with SKIP_IMAGE. T_RRCOPY terminates when the raster list is depleted or
+# the tape is at EOT.
+#
+# Modified 26-JULY-88 to allow for multiple rcopy files on a single tape.
+# This allows for rcopy format data to be archived in multiple files on
+# one tape. The task is still run once per input file. The user is queried
+# (hidden parameter) for the data file to be read. The tape file is actually
+# datafile + 1 because of the ANSI label on each rrcopy tape. (ShJ)
+
+procedure t_rrcopy ()
+
+pointer sp, rp
+bool make_image, print_header, bad_header
+char rcopy_file[SZ_FNAME], iraf_file[SZ_FNAME]
+char out_fname[SZ_FNAME], raster_list[SZ_LINE]
+int rd, ras_number, current_ras, nras, stat, tapefile
+int ranges[3, MAX_RANGES], data_type, init
+
+bool clgetb()
+char clgetc()
+int get_data_type(), position_rcopy(), rc_read_cyber_init(), clgeti()
+int mtopen(), decode_ranges(), get_next_number(), rc_header_read(), strlen()
+int mtfile()
+
+begin
+ # Allocate space on stack for program data structure
+ call smark (sp)
+ call salloc (rp, LEN_RP, TY_STRUCT)
+
+ # Get input filename and open tape drive to second file, skipping label
+ call clgstr ("rcopy_file", rcopy_file, SZ_FNAME)
+ if (mtfile (rcopy_file) == YES) {
+ tapefile = clgeti ("datafile") + 1
+ call mtfname (rcopy_file, tapefile, rcopy_file, SZ_FNAME)
+ }
+ rd = mtopen (rcopy_file, READ_ONLY, SZ_BUFFER)
+ init = rc_read_cyber_init()
+
+ # Get output root filename if it will be needed
+ make_image = clgetb ("make_image")
+ if (make_image) {
+ call clgstr ("iraf_file", iraf_file, SZ_FNAME)
+ data_type = get_data_type (clgetc ("data_type"))
+ if (data_type == ERR)
+ data_type = NOT_SET
+ }
+
+ # Set options
+ print_header = clgetb ("print_header")
+
+ # Expand list of rasters to be read from tape
+ call clgstr ("raster_list", raster_list, SZ_LINE)
+ if (decode_ranges (raster_list, ranges, MAX_RANGES, nras) == ERR)
+ call error (0, "Illegal raster number list")
+
+ ras_number = 0
+ current_ras = 1
+ while (get_next_number (ranges, ras_number) != EOF) {
+ # Position tape to first record of ras_number
+ if (current_ras != ras_number) {
+ iferr (stat = position_rcopy (rd, current_ras, ras_number, rp))
+ call erract (EA_FATAL)
+ if (stat == EOF)
+ break
+ }
+
+ # Assume header is good
+ bad_header = false
+ iferr {
+ stat = rc_header_read (rd, rp)
+ } then {
+ # Error reading header; will attempt to skip raster
+ bad_header = true
+ call erract (EA_WARN)
+ }
+
+ if (stat == EOF) {
+ call printf ("\nRCOPY tape at End of Tape\n")
+ break
+ }
+
+ if (print_header)
+ call rc_list_header (rp, ras_number)
+ call flush (STDOUT)
+
+ if (make_image && ! bad_header) {
+ # Generate output filename
+ call strcpy (iraf_file, out_fname, SZ_FNAME)
+ if (nras > 1) {
+ call sprintf (out_fname[strlen(out_fname)+1], SZ_FNAME,
+ "%03d")
+ call pargi (ras_number)
+ }
+ iferr (call rc_read_image (rd, out_fname, data_type, rp))
+ call erract (EA_FATAL)
+ } else
+ iferr (call rc_skip_image (rd, rp))
+ call erract (EA_FATAL)
+
+ # Increment tape position
+ current_ras = current_ras + 1
+ }
+
+ # Return space allocated for rp, close tape unit
+ call close (rd)
+ call sfree (sp)
+end
+
+
+# POSITION_RCOPY -- Position the tape to the first
+# record of the next raster to be read. Each raster header must
+# be read; each image can then be skipped.
+
+int procedure position_rcopy (rd, current_ras, ras_number, rp)
+
+int rd, current_ras, ras_number
+pointer rp
+int nras_skip, i, stat
+int rc_header_read()
+errchk rc_skip_image
+
+begin
+ nras_skip = ras_number - current_ras
+ for (i=1; i <= nras_skip; i=i+1) {
+ stat = rc_header_read (rd, rp)
+ if (stat == EOF) {
+ call printf ("Cannot position RCOPY tape beyond EOF\n")
+ return (EOF)
+ }
+ call rc_skip_image (rd, rp)
+ current_ras = current_ras + 1
+ }
+ return (OK)
+end