aboutsummaryrefslogtreecommitdiff
path: root/pkg/dataio/reblock
diff options
context:
space:
mode:
authorJoe Hunkeler <jhunkeler@gmail.com>2015-08-11 16:51:37 -0400
committerJoe Hunkeler <jhunkeler@gmail.com>2015-08-11 16:51:37 -0400
commit40e5a5811c6ffce9b0974e93cdd927cbcf60c157 (patch)
tree4464880c571602d54f6ae114729bf62a89518057 /pkg/dataio/reblock
downloadiraf-osx-40e5a5811c6ffce9b0974e93cdd927cbcf60c157.tar.gz
Repatch (from linux) of OSX IRAF
Diffstat (limited to 'pkg/dataio/reblock')
-rw-r--r--pkg/dataio/reblock/mkpkg12
-rw-r--r--pkg/dataio/reblock/reblock.com21
-rw-r--r--pkg/dataio/reblock/reblock.h7
-rw-r--r--pkg/dataio/reblock/reblock.hlp154
-rw-r--r--pkg/dataio/reblock/reblock_file.x416
-rw-r--r--pkg/dataio/reblock/structure.hlp50
-rw-r--r--pkg/dataio/reblock/t_reblock.x214
7 files changed, 874 insertions, 0 deletions
diff --git a/pkg/dataio/reblock/mkpkg b/pkg/dataio/reblock/mkpkg
new file mode 100644
index 00000000..5baf1a30
--- /dev/null
+++ b/pkg/dataio/reblock/mkpkg
@@ -0,0 +1,12 @@
+# Reblock Library
+
+$checkout libpkg.a ../
+$update libpkg.a
+$checkin libpkg.a ../
+$exit
+
+libpkg.a:
+ t_reblock.x reblock.com reblock.h <fset.h> <error.h> <ctype.h>\
+ <mach.h>
+ reblock_file.x reblock.com reblock.h <fset.h> <error.h> <mach.h>
+ ;
diff --git a/pkg/dataio/reblock/reblock.com b/pkg/dataio/reblock/reblock.com
new file mode 100644
index 00000000..35bc652d
--- /dev/null
+++ b/pkg/dataio/reblock/reblock.com
@@ -0,0 +1,21 @@
+# input parameters
+int szb_outblock # size of output block in bytes
+int szb_inrecord # size of input record in bytes
+int szb_outrecord # size of output record in bytes
+int nskip # number blocks (tape) or records (disk) to be skipped
+int ncopy # number of blocks (tape) or records (disk) to be copied
+int padvalue # integer value of padcharacter
+
+# integer switches
+int intape # input tape device
+int outtape # output tape device
+int reblock # reformat?
+int pad_block # pad short blocks
+int pad_record # pad records
+int trim_record # trim records
+int byteswap # swap every other byte
+int wordswap # swap every other word
+
+common /reblock/ szb_outblock, szb_inrecord, szb_outrecord, nskip, ncopy,
+ padvalue, intape, outtape, reblock, pad_block, pad_record,
+ trim_record, byteswap, wordswap
diff --git a/pkg/dataio/reblock/reblock.h b/pkg/dataio/reblock/reblock.h
new file mode 100644
index 00000000..c88d38a8
--- /dev/null
+++ b/pkg/dataio/reblock/reblock.h
@@ -0,0 +1,7 @@
+# define the output parameters
+define BLKS_RD $1[1]
+define BLKS_WRT $1[2]
+define RECS_RD $1[3]
+define RECS_WRT $1[4]
+define LEN_OUTPARAM 4
+
diff --git a/pkg/dataio/reblock/reblock.hlp b/pkg/dataio/reblock/reblock.hlp
new file mode 100644
index 00000000..465314be
--- /dev/null
+++ b/pkg/dataio/reblock/reblock.hlp
@@ -0,0 +1,154 @@
+.help reblock Mar84 dataio
+.ih
+NAME
+reblock -- copy a file on tape or disk with optional reblocking
+.ih
+USAGE
+reblock (infiles, outfiles, file_list)
+.ih
+PARAMETERS
+.ls infiles
+File or device name e.g. "mta1600[2]" or "mta800" or "file1".
+.le
+.ls outfiles
+If multiple file to disk is requested, the ouput file names will be generated
+by concatenating the tape file number onto the output file name.
+.le
+.ls file_list
+List of tape file numbers or ranges delimited by whitespace or commas,
+e.g. "1-3, 5_8".
+File_list is requested only if the magtape input device is specified.
+Files will be read in ascending order regardless of the ordering of the list.
+Reading will terminate silently if EOT is reached, thus a list such as
+"1-999" may be used to read all files on the tape.
+.le
+.ls newtape
+If the output device is magtape, newtape specifies whether the tape is
+blank or contains data.
+Newtape is requested only if no tape file number is specified, e.g. "mta1600".
+.le
+.ls outblock = INDEF
+Size of the output block bytes.
+In the default case and for disk output, the output block size is set to the
+file i/o disk default buffer size.
+.le
+.ls inrecord = INDEF, outrecord = INDEF
+The sizes of the input and output logical records in bytes.
+The default input and output record sizes are set equal to
+the input and output block sizes respectively. If inrecord > outrecord,
+records are trimmed; if inrecord < outrecord, records are padded; if
+inrecord = outrecord, records are simply counted. If only one of inrecord or
+outrecord is set, the undefined parameter defaults to the value of the
+other.
+.le
+.ls nskip = 0
+The number of input blocks (tape input) or records (disk input, size inrecord)
+to be skipped.
+.le
+.ls ncopy = INDEF
+The number of input blocks (tape input) or records
+(disk input, size inrecord) to be copied. Ncopy defaults to a very large number.
+.le
+.ls byteswap = no
+Swap every other byte.
+.le
+.ls wordswap = no
+Swap every other word.
+.le
+.ls pad_block = no
+If pad_block is set, reblock pads trailing blocks until they are outblock
+bytes long, otherwise trailing blocks may be short.
+.le
+.ls padchar = 0
+Single character used to pad blocks or records.
+Padchar is only requested if pad_record or pad_block
+is set. If padchar equals one of the digits 0 through nine, records and
+blocks are padded with the face value of the character, otherwise the
+ASCII value is used.
+.le
+.ls verbose = yes
+Print messages about files, blocks copied etc.
+.le
+.ih
+DESCRIPTION
+
+REBLOCK is a procedure to copy disk or tape resident files to
+disk or tape. Multiple tape files or a single disk input file may be specified.
+If multiple files are output to disk the output file names will be
+generated by concatenating the tape file number onto the output file name.
+The user may request magnetic tape output to begin at a specific file on
+tape, e.g. mta1600[5] in which case file five will be overwritten if it
+exists, or at BOT or EOT. If no file number is specified REBLOCK asks
+whether the tape is new or old and begin writing at BOT or EOT as
+appropriate.
+
+Before beginning the copy, the user may request reblock to skip
+n (default 0) blocks (tape input) or logical records (disk input).
+The user can also specify that
+only n (default all) blocks (tape input) or records (disk input)
+are to be copied. Before the copy the data may be optionally word-swapped
+(default no) and/or byte-swapped (default no). If verbose is specified
+(default yes) reblock prints the input and output file names,
+the number of blocks read and written and the number of records read and
+written.
+
+Reblock
+uses the default buffer sizes supplied by mtio and file i/o to determine the
+maximum number of bytes which can be read in a single read call. For tapes
+this corresponds to the maximum number of bytes per block permitted by the
+device. Mtio will not read more than one block per read call. Therefore the
+actual number of bytes read will be less than or equal to the mtio buffer size.
+For disk files the default buffer size set by IRAF is a multiple of the
+disk block size. If the disk file is smaller than one block
+or the last block is partially full, the number of bytes read
+will be less than the default buffer size. All magtape and disk reads are
+done with the file i/o read procedure and a call to fstati determines the number
+of bytes actually read.
+
+If all the defaults are set, a binary copy is performed.
+In tape to tape copies the block and record sizes are preserved,
+but the density may
+be changed by specifying the appropriate output file name e.g. mta800 or
+mta1600.
+Reblocking occurs in tape to disk transfers, if records, are trimmed,
+padded or counted, or if blocks are padded.
+If a disk to tape transfer is requested
+the output block size will be the default file i/o buffer size.
+The last block in a file may be short. If uniform sized blocks are
+desired, pad_block must be set, in which case trailing partially filled
+blocks will be padded with padchar.
+
+Logical records are distinguished from blocks (physical records).
+The input and output record sizes default to
+the size of the input and output blocks respectively.
+Logical records may be shorter or longer than the block sizes.
+.ih
+EXAMPLES
+
+Copy a magnetic tape preserving the record sizes but changing
+the density from 800 bpi to 1600 bpi.
+
+.nf
+ da> reblock mtb800, "mta1600[1]", "1-999"
+.fi
+
+Reblock a magnetic tape changing the block size from 4000 bytes to 8000
+bytes and padding the last block.
+
+.nf
+ da> reblock mtb1600, "mta1600[1]", "1-999", outb=8000, padb+
+.fi
+
+Trim the records of a disk file.
+
+.nf
+ da> reblock input, output, inrec=80, outrec=72
+.fi
+
+Pad the records of a disk file with blanks.
+
+.nf
+ da> reblock input, output, inrec=81, outrec=82, padchar=" "
+.fi
+
+.endhelp
diff --git a/pkg/dataio/reblock/reblock_file.x b/pkg/dataio/reblock/reblock_file.x
new file mode 100644
index 00000000..2801a1b1
--- /dev/null
+++ b/pkg/dataio/reblock/reblock_file.x
@@ -0,0 +1,416 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <error.h>
+include <fset.h>
+include <mach.h>
+include "reblock.h"
+
+# REB_REBLOCK_FILE -- Copy and optionally reblock files.
+
+procedure reb_reblock_file (in_fname, out_fname, outparam)
+
+char in_fname[ARB] # input file name
+char out_fname[ARB] # output file name
+int outparam[ARB] # output parameters
+
+char padchar
+int in, out, sz_charsin, sz_charsout, mov_nbytes, rem_in, rem_out
+int bytes_read, ip, op, i, first_byte, nchars, rec_count, ntrim
+long offset
+pointer inbuf, outbuf
+
+int mtopen(), reb_roundup(), read(), reb_skipover(), fstati(), open()
+errchk open, mtopen, read, awriteb, awaitb, close, mfree, malloc, flush
+errchk reb_write_block, reb_pad_block, reb_pad_record, reb_skipover
+include "reblock.com"
+
+begin
+ # Open input and output files
+ in = mtopen (in_fname, READ_ONLY, 0)
+ out = NULL
+
+ # Allocate space for input buffer.
+ sz_charsin = fstati (in, F_BUFSIZE)
+ call malloc (inbuf, sz_charsin, TY_CHAR)
+ outbuf = NULL
+
+ # Skip over n input blocks (tape) or records (disk).
+ first_byte = 1
+ if (intape == YES) {
+ for (i=1; i <= nskip; i = i + 1) {
+ nchars = read (in, Memc[inbuf], sz_charsin)
+ if (nchars == EOF)
+ call error (1,"Skipped past EOF on input.")
+ }
+ } else {
+ first_byte = reb_skipover (in, szb_inrecord, nskip)
+ if (first_byte == EOF)
+ call error (2, "Skipped past EOF on input.")
+ }
+
+ # Initialize the input and output block and record counters
+ BLKS_RD(outparam) = 0
+ BLKS_WRT(outparam) = 0
+ RECS_RD(outparam) = 0
+ RECS_WRT(outparam) = 0
+
+ # Initalize the record counter.
+ rec_count = 0
+
+ # Set of the offset in output file for asyncrhronous i/o.
+ offset = 1
+
+ # Loop over the input blocks.
+ repeat {
+
+ # Read a block and update block counter.
+ nchars = read (in, Memc[inbuf], sz_charsin)
+ if (nchars == EOF)
+ break
+ bytes_read = nchars * SZB_CHAR
+ if (mod (fstati (in, F_SZBBLK), SZB_CHAR) != 0)
+ bytes_read = bytes_read - mod (fstati (in, F_SZBBLK), SZB_CHAR)
+ BLKS_RD(outparam) = BLKS_RD(outparam) + 1
+
+ # Align to first byte.
+ if (rec_count == 0 && first_byte > 1) {
+ bytes_read = bytes_read - first_byte + 1
+ call bytmov (Memc[inbuf],first_byte, Memc[inbuf],1, bytes_read)
+ }
+
+ # Open the output file. This has been moved from the beginning
+ # of the routine to avoid a magtape problem.
+ # driver problem.
+ if (BLKS_RD(outparam) == 1) {
+ if (outtape == NO)
+ out = open (out_fname, NEW_FILE, BINARY_FILE)
+ else
+ out = mtopen (out_fname, WRITE_ONLY, 0)
+ }
+
+ # Binary copy.
+ if (reblock == NO) {
+
+ RECS_RD(outparam) = BLKS_RD(outparam)
+ call reb_write_block (out, Memc[inbuf], bytes_read, offset,
+ byteswap, wordswap)
+ BLKS_WRT(outparam) = BLKS_WRT(outparam) + 1
+ RECS_WRT(outparam) = BLKS_WRT(outparam)
+
+ # Reblock.
+ } else {
+
+ # Initialize reblocking parameters after first read.
+ if (BLKS_RD(outparam) == 1) {
+
+ # Initialize block and record sizes
+ if (IS_INDEFI(szb_inrecord))
+ szb_inrecord = sz_charsin * SZB_CHAR
+ if (IS_INDEFI(szb_outblock))
+ szb_outblock = fstati (out, F_BUFSIZE) * SZB_CHAR
+ if (IS_INDEFI(szb_outrecord))
+ szb_outrecord = szb_outblock
+
+ # Set pad character.
+ if (pad_record == YES || pad_block == YES) {
+ padchar = char (padvalue)
+ call chrpak (padchar, 1, padchar, 1, 1)
+ }
+
+ # Allocate space for the output buffer.
+ sz_charsout = reb_roundup (szb_outblock, SZB_CHAR) /
+ SZB_CHAR
+ call malloc (outbuf, sz_charsout, TY_CHAR)
+
+ # Intialize the record remainder counters
+ rem_in = szb_inrecord
+ rem_out = szb_outrecord
+
+ # Initialize input and output buffer pointers
+ ip = 1
+ op = 1
+ }
+
+ # Loop over the input buffer.
+ repeat {
+
+ # Calculate the number of bytes to be moved.
+ mov_nbytes = min (bytes_read - ip + 1,
+ rem_in, rem_out, szb_outblock - op + 1)
+ call bytmov (Memc[inbuf], ip, Memc[outbuf], op, mov_nbytes)
+
+ # Update the remainders
+ rem_in = rem_in - mov_nbytes
+ if (rem_in == 0)
+ rem_in = szb_inrecord
+ rem_out = rem_out - mov_nbytes
+ if (rem_out == 0)
+ rem_out = szb_outrecord
+
+ # Update the input and output buffer pointers.
+ ip = ip + mov_nbytes
+ op = op + mov_nbytes
+
+ # Pad records.
+ if (pad_record == YES && rem_in == szb_inrecord) {
+
+ # Do the padding.
+ if (mov_nbytes != 0) {
+ RECS_RD(outparam) = RECS_RD(outparam) + 1
+ call reb_pad_record (Memc[outbuf], op, rem_out,
+ szb_outblock, szb_outrecord, padchar)
+ } else if (rem_out < szb_outrecord)
+ call reb_pad_record (Memc[outbuf], op, rem_out,
+ szb_outblock, szb_outrecord, padchar)
+
+ # Increment the output record counter.
+ if (rem_out == szb_outrecord)
+ RECS_WRT(outparam) = RECS_WRT(outparam) + 1
+ else if (rem_out < szb_outrecord)
+ rem_in = 0
+ }
+
+ # If the output buffer is exhausted, output block of data.
+ if (op > szb_outblock) {
+ call reb_write_block (out, Memc[outbuf], szb_outblock,
+ offset, byteswap, wordswap)
+ BLKS_WRT(outparam) = BLKS_WRT(outparam) + 1
+ op = 1
+ }
+
+ # Trim records.
+ if (trim_record == YES && rem_out == szb_outrecord) {
+
+ # Do the trimming.
+ if (mov_nbytes != 0)
+ RECS_WRT(outparam) = RECS_WRT(outparam) + 1
+ ntrim = min (rem_in, bytes_read - ip + 1)
+ ip = ip + ntrim
+ rem_in = rem_in - ntrim
+ if (rem_in == 0)
+ rem_in = szb_inrecord
+
+ # Increment the record counter.
+ if (rem_in == szb_inrecord)
+ RECS_RD(outparam) = RECS_RD(outparam) + 1
+ else if (rem_in < szb_inrecord)
+ rem_out = 0
+ }
+
+ # Count the records.
+ if (pad_record == NO && trim_record == NO) {
+ if (szb_inrecord == sz_charsin * SZB_CHAR)
+ RECS_RD(outparam) = BLKS_RD(outparam)
+ else if (rem_in == szb_inrecord)
+ RECS_RD(outparam) = RECS_RD(outparam) + 1
+ if (rem_out == szb_outrecord)
+ RECS_WRT(outparam) = RECS_WRT(outparam) + 1
+ }
+
+ # Quit if ncopy records has been reached.
+ if (intape == NO && RECS_RD(outparam) == ncopy)
+ break
+
+ } until (ip > bytes_read)
+
+ # Reset the input buffer pointer
+ ip = 1
+ }
+
+ # Update the record counter.
+ if (intape == YES)
+ rec_count = BLKS_RD(outparam)
+ else
+ rec_count = RECS_RD(outparam)
+
+ } until (rec_count >= ncopy)
+
+ # Output remainder of data
+ if (reblock == YES) {
+
+ # Pad last record if short.
+ if (pad_record == YES) {
+ if (rem_in < szb_inrecord)
+ RECS_RD(outparam) = RECS_RD(outparam) + 1
+ if (rem_out < szb_outrecord)
+ RECS_WRT(outparam) = RECS_WRT(outparam) + 1
+ while (rem_out < szb_outrecord) {
+ call reb_pad_record (Memc[outbuf], op, rem_out,
+ szb_outblock, szb_outrecord, padchar)
+ if (op > szb_outblock) {
+ call reb_write_block (out, Memc[outbuf], szb_outblock,
+ offset, byteswap, wordswap)
+ BLKS_WRT(outparam) = BLKS_WRT(outparam) + 1
+ op = 1
+ }
+ }
+ }
+
+ # Pad last block if short.
+ if (pad_block == YES && op > 1)
+ call reb_pad_block (Memc[outbuf], op, rem_out, outparam,
+ szb_outblock, szb_outrecord, padchar)
+
+ # Write last block
+ if (op > 1) {
+ call reb_write_block (out, Memc[outbuf], op - 1, offset,
+ byteswap, wordswap)
+ op = 1
+ BLKS_WRT(outparam) = BLKS_WRT(outparam) + 1
+ if (pad_record == YES && rem_out < szb_outrecord)
+ RECS_WRT(outparam) = RECS_WRT(outparam) + 1
+ else if (rem_out < szb_outrecord)
+ RECS_WRT(outparam) = RECS_WRT(outparam) + 1
+ }
+
+ }
+
+ call mfree (inbuf, TY_CHAR)
+ if (outbuf != NULL)
+ call mfree (outbuf, TY_CHAR)
+ call close (in)
+ if (out != NULL)
+ call close (out)
+end
+
+
+# REB_PAD_RECORD -- Procedure for padding records.
+
+procedure reb_pad_record (buffer, op, rem_out, szb_outblock, szb_outrecord,
+ padchar)
+
+char buffer[ARB], padchar
+int szb_outblock, szb_outrecord, op, rem_out
+int i, junk
+
+begin
+ junk = rem_out
+ for (i = 1; i <= junk && op <= szb_outblock; i = i + 1) {
+ call bytmov (padchar, 1, buffer, op, 1)
+ op = op + 1
+ rem_out = rem_out - 1
+ }
+
+ if (rem_out == 0)
+ rem_out = szb_outrecord
+end
+
+
+# REB_PAD_BLOCK -- Procedure to pad the last block so that all output blocks
+# will have the same size.
+
+procedure reb_pad_block (buffer, op, rem_out, outparam, szb_outblock,
+ szb_outrecord, padchar)
+
+char buffer[ARB] # data to be padded
+int op # pointer to first element for padding
+int rem_out # number of remaining bytes to be padded in a record
+int outparam[ARB] # output parameters, number of records, blocks written
+int szb_outblock # size in bytes of output block
+int szb_outrecord # size in bytes of an output record
+char padchar # character used for padding
+
+int i, junk
+
+begin
+ junk = szb_outblock - op + 1
+ for (i = 1; i <= junk; i = i + 1) {
+ call bytmov (padchar, 1, buffer, op, 1)
+ op = op + 1
+ rem_out = rem_out - 1
+ if (rem_out == 0) {
+ rem_out = szb_outrecord
+ RECS_WRT(outparam) = RECS_WRT(outparam) + 1
+ }
+ }
+end
+
+
+# REB_WRITE_BLOCK -- Procedure to write blocks using the asynchronous read
+# and write functions in file i/o. Writing must occur on block boundaries.
+
+procedure reb_write_block (fd, buffer, nbytes, offset, byteswap, wordswap)
+
+int fd # output file descriptor
+char buffer[ARB] # data to be output
+int nbytes # number of bytes of data
+long offset # offset in chars in output file for writing
+int byteswap # swap every other byte before output
+int wordswap # swap every other word before output
+
+int nbread
+int awaitb()
+errchk awriteb, awaitb
+
+begin
+ if (byteswap == YES)
+ call bswap2 (buffer, 1, buffer, 1, nbytes)
+ if (wordswap == YES)
+ call bswap4 (buffer, 1, buffer, 1, nbytes)
+ call awriteb (fd, buffer, nbytes, offset)
+ nbread = awaitb (fd)
+ if (nbread == ERR)
+ call error (3, "Error writing block data")
+ else
+ offset = offset + nbread
+end
+
+
+# REB_SKIPOVER -- Procedure to find the first byte containing data given the
+# input block size and the number of input blocks to be skipped.
+
+int procedure reb_skipover (fd, szb_inblock, nskip)
+
+int fd # file descriptor
+int szb_inblock # size of an input block
+int nskip # number of blocks to skip
+
+int first_byte
+long szb_skip, szb_physkip, skip_diff, sz_charoff, loff
+long fstatl()
+int reb_roundup()
+errchk fstatl, seek
+
+begin
+ szb_skip = long (szb_inblock) * long (nskip)
+ szb_physkip = reb_roundup (szb_skip, SZB_CHAR)
+ skip_diff = szb_physkip - szb_skip
+
+ if (skip_diff == 0) {
+ sz_charoff = (szb_physkip / SZB_CHAR) + 1
+ first_byte = 1
+ } else {
+ sz_charoff = (szb_physkip / SZB_CHAR) - 1
+ first_byte = int (szb_skip - (SZB_CHAR * sz_charoff) + 1)
+ }
+
+ loff = long (sz_charoff)
+
+ if (loff > fstatl (fd, F_FILESIZE)) {
+ call seek (fd, EOF)
+ return (EOF)
+ } else {
+ call seek (fd, loff)
+ return (first_byte)
+ }
+end
+
+
+# REB_ROUNDUP -- Procedure to round a number to the next highest number
+# divisible by base.
+
+int procedure reb_roundup (number, base)
+
+int number # number to be rounded upwards
+int base # base for rounding
+
+int value
+
+begin
+ if (mod(number, base) == 0)
+ return (number)
+ else {
+ value = (number/base + 1) * base
+ return (value)
+ }
+end
diff --git a/pkg/dataio/reblock/structure.hlp b/pkg/dataio/reblock/structure.hlp
new file mode 100644
index 00000000..1a7c5221
--- /dev/null
+++ b/pkg/dataio/reblock/structure.hlp
@@ -0,0 +1,50 @@
+.help gcopy "Program Structure"
+.sh
+Program Structure
+.nf
+t_bincopy()
+# Returns when file list is finished or EOT reached.
+
+ read_file (in_fname, out_fname, outparam)
+ Returns when an EOF is encountered on read.
+
+ skipover (fd, szb_outblock, nskip)
+ # Returns the offset of the first data byte in the first char
+ # to contain data of interest or EOF
+
+ record_pad (szb_outblock, szb_outrecord, padchar, buffer, op, rem_out)
+
+ block_pad (szb_outblock, szb_outrecord, padchar, buffer, op, rem_out,
+ outparam)
+.fi
+.sh
+BINCOPY Structure Summary
+.ls t_bincopy
+The main program gets the input and output filenames, creates a list of
+files to be processed and gets the program parameters.
+For each file in the input list READFILE is called,
+and the input and output file names, blocks read and written and records read
+and written are printed.
+The program terminates when the input file list is exhausted or EOT is reached.
+.ls read_file
+READ_FILE opens the input and output devices, allocates space for the input
+and output buffers and copies the data optionally skipping data
+and byteswapping and/or wordswapping the data.
+The routine terminates when an EOF is encountered on a read.
+READ_FILE calls SKIPOVER to find the first data byte of interest and
+RECORD_PAD and BLOCK_PAD to pad records and blocks respectively.
+.ls skipover
+SKIPOVER seeks to the first char containing data of interest and calculates
+the offset in that char of the first byte of interest. Returns the offset
+or EOF if the requested position is past EOF.
+.le
+.ls record_pad
+Record_pad pads input records of szb_inrecord bytes long to output records
+szb_outrecord long.
+.le
+.ls block_pad
+Pads short blocks to size szb_outblock.
+.le
+.le
+.le
+.endhelp
diff --git a/pkg/dataio/reblock/t_reblock.x b/pkg/dataio/reblock/t_reblock.x
new file mode 100644
index 00000000..09c86a9a
--- /dev/null
+++ b/pkg/dataio/reblock/t_reblock.x
@@ -0,0 +1,214 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <fset.h>
+include <error.h>
+include <ctype.h>
+include <mach.h>
+include "reblock.h"
+
+define MAX_RANGES 100
+define SZ_PADCHAR 10
+
+# T_REBLOCK -- Procedure to copy binary files optionally changing the blocking
+# factor. Further documentation in reblock.hlp.
+
+procedure t_reblock ()
+
+char infiles[SZ_FNAME] # list of input files
+char file_list[SZ_LINE] # list of tape file numbers
+char outfiles[SZ_FNAME] # list of output files
+char padchar[SZ_PADCHAR] # character for padding blocks and records
+bool verbose # print messages ?
+
+char in_fname[SZ_FNAME], out_fname[SZ_FNAME], cval
+int inlist, outlist, len_inlist, len_outlist, file_number, file_cnt
+int range[2 * MAX_RANGES + 1]
+int outparam[LEN_OUTPARAM], offset, ip
+
+bool clgetb()
+int fstati(), mtfile(), mtneedfileno(), fntopnb(), fntlenb(), fntgfnb()
+int decode_ranges(), btoi(), clgeti(), get_next_number(), cctoc()
+include "reblock.com"
+
+begin
+ # Flush on a newline if the output is not redirected.
+ if (fstati (STDOUT, F_REDIR) == NO)
+ call fseti (STDOUT, F_FLUSHNL, YES)
+
+ # Get the input and output file(s).
+ call clgstr ("infiles", infiles, SZ_FNAME)
+ call clgstr ("outfiles", outfiles, SZ_FNAME)
+
+ # Get the input file names.
+ if (mtfile (infiles) == YES) {
+ inlist = NULL
+ intape = YES
+ if (mtneedfileno (infiles) == YES)
+ call clgstr ("file_list", file_list, SZ_LINE)
+ else
+ call strcpy ("1", file_list, SZ_LINE)
+ } else {
+ inlist = fntopnb (infiles, NO)
+ len_inlist = fntlenb (inlist)
+ intape = NO
+ if (len_inlist > 0) {
+ call sprintf (file_list, SZ_LINE, "1-%d")
+ call pargi (len_inlist)
+ } else
+ call strcpy ("0", file_list, SZ_LINE)
+ }
+
+ # Decode the tape file number list.
+ if (decode_ranges (file_list, range, MAX_RANGES, len_inlist) == ERR)
+ call error (0, "Illegal file number list.")
+ offset = clgeti ("offset")
+
+ # Get the output file names.
+ if (mtfile (outfiles) == YES) {
+ outlist = NULL
+ len_outlist = len_inlist
+ outtape = YES
+ if (mtneedfileno (outfiles) == YES) {
+ if (! clgetb ("newtape"))
+ call mtfname (outfiles, EOT, out_fname, SZ_FNAME)
+ else
+ call mtfname (outfiles, 1, out_fname, SZ_FNAME)
+ } else
+ call strcpy (outfiles, out_fname, SZ_FNAME)
+ } else {
+ outlist = fntopnb (outfiles, NO)
+ len_outlist = fntlenb (outlist)
+ outtape = NO
+ }
+ if ((len_inlist > 1) && (len_outlist != 1) &&
+ (len_outlist != len_inlist))
+ call error (0,
+ "The number of input and output files is not equal")
+
+ # Get the block and record sizes.
+ szb_outblock = clgeti ("outblock")
+ if (outtape == NO)
+ szb_outblock = INDEFI
+ szb_inrecord = clgeti ("inrecord")
+ szb_outrecord = clgeti ("outrecord")
+ if (IS_INDEFI(szb_inrecord) && !IS_INDEFI(szb_outrecord))
+ szb_inrecord = szb_outrecord
+ if (IS_INDEFI(szb_outrecord) && !IS_INDEFI(szb_inrecord))
+ szb_outrecord = szb_inrecord
+
+ # Get the pad and trim parameters.
+ pad_block = btoi (clgetb ("pad_block"))
+ if (szb_inrecord < szb_outrecord)
+ pad_record = YES
+ else
+ pad_record = NO
+ if (szb_inrecord > szb_outrecord)
+ trim_record = YES
+ else
+ trim_record = NO
+ if (pad_block == YES || pad_record == YES) {
+ call clgstr ("padchar", padchar, SZ_PADCHAR)
+ ip = 1
+ if (cctoc (padchar, ip, cval) <= 0)
+ cval = ' '
+ if (IS_DIGIT (cval))
+ padvalue = TO_INTEG (cval)
+ else
+ padvalue = cval
+ }
+
+ # Tape to disk always requires reblocking.
+ if (intape == YES && outtape == NO)
+ reblock = YES
+ else if (pad_record == YES || pad_block == YES || trim_record == YES)
+ reblock = YES
+ else if (!IS_INDEFI(szb_outblock) || !IS_INDEFI(szb_inrecord) ||
+ !IS_INDEFI(szb_outrecord))
+ reblock = YES
+ else
+ reblock = NO
+
+ # Get remaining parameters.
+ nskip = max (0, clgeti ("skipn"))
+ ncopy = clgeti ("copyn")
+ if (IS_INDEFI(ncopy))
+ ncopy = MAX_INT
+ byteswap = btoi (clgetb ("byteswap"))
+ wordswap = btoi (clgetb ("wordswap"))
+ verbose = clgetb ("verbose")
+
+ # Loop through the files
+ file_cnt = 1
+ file_number = 0
+ while (get_next_number (range, file_number) != EOF) {
+
+ # Construct the input file name.
+ if (intape == YES) {
+ if (mtneedfileno (infiles) == YES)
+ call mtfname (infiles, file_number, in_fname, SZ_FNAME)
+ else
+ call strcpy (infiles, in_fname, SZ_FNAME)
+ } else if (fntgfnb (inlist, in_fname, SZ_FNAME) != EOF)
+ ;
+
+ # Construct the output file name.
+ if (outtape == NO) {
+ if (len_inlist > 1 && len_outlist == 1) {
+ call sprintf (out_fname[1], SZ_FNAME, "%s%03d")
+ call pargstr (outfiles)
+ if (intape == YES)
+ call pargi (file_number + offset)
+ else
+ call pargi (file_cnt)
+ } else if (fntgfnb (outlist, out_fname, SZ_FNAME) != EOF)
+ ;
+ } else if (file_cnt == 2)
+ call mtfname (out_fname, EOT, out_fname, SZ_FNAME)
+
+ iferr {
+
+ if (verbose) {
+ call printf ("File: %s -> %s: ")
+ call pargstr (in_fname)
+ call pargstr (out_fname)
+ }
+
+ call reb_reblock_file (in_fname, out_fname, outparam)
+
+ if (verbose) {
+ if (intape == YES)
+ call printf ("[skip %d blks] ")
+ else
+ call printf ("[skip %d recs] ")
+ call pargi (nskip)
+ call printf ("blks r/w %d/%d ")
+ call pargi (BLKS_RD(outparam))
+ call pargi (BLKS_WRT(outparam))
+ if (reblock == YES) {
+ call printf ("recs r/w %d/%d\n")
+ call pargi (RECS_RD(outparam))
+ call pargi (RECS_WRT(outparam))
+ } else
+ call printf ("\n")
+ }
+
+ } then {
+ call flush (STDOUT)
+ call eprintf ("Cannot read file %s\n")
+ call pargstr (in_fname)
+ } else if (BLKS_RD(outparam) == 0) {
+ if (verbose) {
+ call printf ("Empty file: %s\n")
+ call pargstr (in_fname)
+ }
+ break
+ } else {
+ file_cnt = file_cnt + 1
+ }
+ }
+
+ if (inlist != NULL)
+ call fntclsb (inlist)
+ if (outlist != NULL)
+ call fntclsb (outlist)
+end