STScI Logo

t_mtexamine



# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.

include <error.h>
include <fset.h>
include <printf.h>
include <mach.h>

define	MAX_RANGES	100
define	LEN_LINE	80
define	TAPE_BYTE	8
define	TWO_TO_EIGHT	256
define	FIELD_INDEX	5
define	NFORMATS	5


# MTEXAMINE -- Examine one or more magtape files, counting the number and size
# of the records in a file, and the number of files on the tape.

procedure t_mtexamine()

int	nfiles, file_number, ndumps, nrecords
int	file_range[2*MAX_RANGES+1], rec_range[2*MAX_RANGES+1]
pointer	sp, tape_name, tape_file, file_list, rec_list

bool	clgetb()
char	clgetc()
int	fstati(), mtfile(), mtneedfileno(), decode_ranges(), get_next_number()
int	mt_examine(), mt_get_format(), clgeti(), btoi()
include "mtexamine.com"

begin
	# Allocate working space.
	call smark (sp)
	call salloc (tape_name, SZ_FNAME, TY_CHAR)
	call salloc (tape_file, SZ_FNAME, TY_CHAR)
	call salloc (file_list, SZ_LINE, TY_CHAR)
	call salloc (rec_list,  SZ_LINE, TY_CHAR)

	# Flush STDOUT on a newline only if output is not redirected.
	if (fstati (STDOUT, F_REDIR) == NO)
	    call fseti (STDOUT, F_FLUSHNL, YES)

        # Get input file(s).
        call clgstr ("tape_file", Memc[tape_file], SZ_FNAME)
        if (mtfile (Memc[tape_file]) == NO)
	    call strcpy ("1", Memc[file_list], SZ_LINE)
	else if (mtneedfileno (Memc[tape_file]) == NO)
	    call strcpy ("1", Memc[file_list], SZ_LINE)
        else
	    call clgstr ("file_list", Memc[file_list], SZ_LINE)
        if (decode_ranges (Memc[file_list],file_range,MAX_RANGES,nfiles) == ERR)
	    call error (0, "Illegal file number list.")

        # Get dump parameters
        dump_records = btoi (clgetb ("dump_records"))
        if (dump_records == YES) {
	    call clgstr ("rec_list", Memc[rec_list], SZ_LINE)
	    if (decode_ranges (Memc[rec_list], rec_range, MAX_RANGES,
		ndumps) == ERR)
	        call error (0, "Illegal record list.")
	    byteswap = btoi (clgetb ("swapbytes"))
	    byte_chunk = clgeti ("byte_chunk")
	    if (byte_chunk < 1 || byte_chunk > (SZ_LONG * SZB_CHAR))
		call error (0, "Illegal byte chunk size.")
	    output_format = mt_get_format (clgetc ("output_format"))
	    if (output_format == ERR)
		call error (0, "Illegal format.")
	    if (byte_chunk != 1 && output_format == FMT_CHAR)
		call error (0, "Cannot output integers as chars.")
        }

        # Loop over files
	file_number = 0
        while (get_next_number (file_range, file_number) != EOF) {

	    if (mtfile (Memc[tape_file]) == YES &&
		mtneedfileno (Memc[tape_file]) == YES)
		call mtfname (Memc[tape_file], file_number, Memc[tape_name],
		    SZ_FNAME)
	    else
	        call strcpy (Memc[tape_file], Memc[tape_name], SZ_FNAME)

	    iferr {
	        nrecords = mt_examine (Memc[tape_name], rec_range)
	    } then {
		call eprintf ("Error reading file: %s\n")
		    call pargstr (Memc[tape_name])
		call erract (EA_WARN)
		break
	    } else if (nrecords == 0) {
	        call printf ("Tape at EOT\n")
		break
	    }

        }

	call sfree (sp)
end


# MT_EXAMINE -- Procedure to examine a tape file. If dump_record is
# no mtexamine gives a summary of the record structure of the file,
# otherwise the specified records are dumped.

int procedure mt_examine (tape_file, dump_range)

char	tape_file[ARB]		# input file name
int	dump_range[ARB]		# range of records to be dumped

pointer	sp, inbuf, pchar, junk
int	in, bufsize, totrecords, nrecords, totbytes, last_recsize, nbadrec
int	stat, rec_number, next_dump, recsize, nelems, vals_per_line, field_len
long	maxval, max_plusint, twice_max_plusint

int	mtopen(), fstati(), get_next_number(), read(), gltoc()
errchk	mtopen, malloc, read, mfree, close
include "mtexamine.com"

begin
	call smark (sp)
	call salloc (junk, SZ_FNAME, TY_CHAR)

	in = mtopen (tape_file, READ_ONLY, 0)
	bufsize = fstati (in, F_BUFSIZE)
	call salloc (pchar, bufsize, TY_CHAR)

	call printf ("File %s:\n")
	    call pargstr (tape_file)

	totrecords = 0
	nrecords = 0
	totbytes = 0
	nbadrec  = 0
	last_recsize = 0

	# Prepare formatting parameters for dumping records.
	if (dump_records == YES) {
	    call salloc (inbuf, bufsize * SZB_CHAR, TY_LONG)
	    rec_number = 0
	    next_dump = get_next_number (dump_range, rec_number)
	    maxval = 2 ** (byte_chunk * TAPE_BYTE - 1) - 1
	    field_len = gltoc (maxval, Memc[junk], SZ_FNAME, TAPE_BYTE) + 1
	    vals_per_line = (LEN_LINE - FIELD_INDEX) / (field_len + 1)
	    if (output_format == FMT_DECIMAL && byte_chunk > 1 &&
	    		byte_chunk < (SZ_LONG * SZB_CHAR)) {
	        max_plusint = maxval + 1
	        twice_max_plusint = 2 * max_plusint
	    }
	}

	# Loop through the records.
	repeat {
	    iferr (stat = read (in, Memc[pchar], bufsize)) {
		call fseti (in, F_VALIDATE, last_recsize / SZB_CHAR)
		nbadrec = nbadrec + 1
	        call printf ("\tRead error on record: %d\n")
		    call pargi (totrecords + 1)
		stat = read (in, Memc[pchar], bufsize)
	    }
	    if (stat == EOF)
		break

	    recsize = fstati (in, F_SZBBLK)
	    if (dump_records == NO) {
	        if (nrecords == 0) {
		    nrecords = 1
		    last_recsize = recsize
		} else if (recsize == last_recsize) {
		    nrecords = nrecords + 1
		} else {
		    call printf ("\t%d %d-byte records\n")
		        call pargi (nrecords)
		        call pargi (last_recsize)
		    nrecords = 1
		    last_recsize = recsize
		}
	    } else if (next_dump != EOF && rec_number == totrecords + 1) {
	        call printf ("    Record %d,")
		    call pargi (totrecords + 1)
		call printf (" %d bytes,")
		    call pargi (recsize)
		nelems = recsize / byte_chunk
		call printf (" %d elements")
		    call pargi (nelems)
		call mt_bytupkl (Memc[pchar], Meml[inbuf], recsize, byte_chunk,
		    byteswap)
		call mt_dump (Meml[inbuf], nelems, field_len, vals_per_line,
		    max_plusint, twice_max_plusint)
		next_dump = get_next_number (dump_range, rec_number)
	    }

	    totrecords = totrecords + 1
	    totbytes = totbytes + recsize
	 }

	if (nrecords > 0 && dump_records == NO) {
	    call printf ("\t%d %d-byte records\n")
	        call pargi (nrecords)
	        call pargi (last_recsize)
 	}

	# Print total number of records and bytes
	if (dump_records == YES) {
	    call printf ("    Total %d records, %d bytes\n")
	        call pargi (totrecords)
	        call pargi (totbytes)
	} else { 
	    call printf ("\tTotal %d records, %d bytes")
	        call pargi (totrecords)
	        call pargi (totbytes)
	    if (nbadrec > 0) {
		call printf (" [%d bad records]")
		    call pargi (nbadrec)
	    }
	    call printf ("\n")
	}

	call close (in)

	call sfree (sp)
	return (totrecords)
end


# MT_DUMP -- Procedure to format and dump a tape record in chars, shorts or
# longs in char, decimal, octal, unsigned decimal or hexadecimal format.

procedure mt_dump (buffer, nelems, field_len, vals_per_line, max_plusint,
	twice_max_plusint)

int	nelems, field_len, vals_per_line
long	buffer[ARB], max_plusint, twice_max_plusint

int	i, nchars
char	ch, outstr[SZ_FNAME]
int	ctocc()
include "mtexamine.com"

begin
	for (i = 1; i <= nelems; i = i + 1) {
	    if (mod (i, vals_per_line) == 1) {
		call printf ("\n%*d:")
		    call pargi (FIELD_INDEX)
		    call pargi (i)
	    }
	    if (output_format == FMT_CHAR) {
		ch = buffer[i]
		nchars = ctocc (ch, outstr, SZ_FNAME)
		call printf ("%*s")
		    call pargi (field_len)
		    call pargstr (outstr)
	    } else {
		if (output_format == FMT_DECIMAL && byte_chunk > 1
			        && byte_chunk < (SZ_LONG * SZB_CHAR))
		    call mt_sign_convert (buffer[i], 1, max_plusint,
		    		    twice_max_plusint)
		call printf ("%**")
		    call pargi (field_len)
		    call pargc (output_format)
		    call pargl (buffer[i])
	    }
	}

	call printf ("\n")
end


# MT_GET_FORMAT -- Procedure to return the appropriate output format.

int procedure mt_get_format (c)

char	c
int	i, format_code[NFORMATS]
int	stridx()
string	formats "cdoxu"
data	format_code /FMT_CHAR, FMT_DECIMAL, FMT_OCTAL, FMT_HEX, FMT_UNSIGNED/

begin
	i = stridx (c, formats)
	if ( i == 0)
	    return (ERR)
	else
	    return (format_code[i])
end


# MT_BYTUPKL -- Procedure to unpack an  array in chunks byte_chunk bytes long
# into a long array with optional byteswapping.

procedure mt_bytupkl (a, b, nbytes, byte_chunk, byteswap)

char	a[ARB]		# input buffer
long	b[ARB]		# output array
int	nbytes		# number of bytes
int	byte_chunk	# number of bytes to be formatted, swapped etc.
int	byteswap	# swap bytes

int	op, i, j, rem
long	sum

begin
	op = 1

	# Unpack unsigned bytes into a long integer array
	call achtbl (a, b, nbytes)

	# Flip bytes if necessary
	if (byteswap == YES && byte_chunk > 1) {
	    for (i = 1; i <= nbytes - byte_chunk + 1; i = i + byte_chunk)
		call mt_aflipl (b[i], byte_chunk)
	}

	# Convert the bytes into unsigned integers
	for (i = 1; i <= nbytes - byte_chunk + 1; i = i + byte_chunk) {
	    sum = 0
	    for (j = 1; j <= byte_chunk; j = j + 1) {
		sum = sum + TWO_TO_EIGHT ** (byte_chunk - j) *
			b[i + j - 1]
	    }
	    b[op] = sum
	    op = op + 1
	}

	# Convert remaining bytes
	rem = nbytes -  i + 1
	if (rem > 0) {
	    if (byteswap == YES && byte_chunk > 1)
	        call mt_aflipl (b[i], rem)
	    sum = 0
	    for (j = 1; j <= rem; j = j + 1)
	        sum = sum + TWO_TO_EIGHT ** (rem - j) *
			b[i + j - 1]
	    b[op] = sum
	}
end


# MT_AFLIPL -- Procedure to flip a long integer array in place.

procedure mt_aflipl (buf, npix)

long	buf[npix]	# array to be flipped
int	npix		# number of elements in array

int	n_total, n_half, i, j

begin
	n_half = npix / 2
	n_total = npix + 1
	for (i = 1; i <= n_half; i = i + 1) {
	    j = buf[i]
	    buf[i] = buf[n_total - i]
	    buf[n_total - i] = j
	}
end


# MT_SIGN_CONVERT -- Procedure to convert unsigned long integers in the range
# 0 to twice_max_plusint - 1 to integers in the range  - max_plusint
# to max_plusint - 1.

procedure mt_sign_convert (b, nelems, max_plusint, twice_max_plusint)

long	b[nelems]		# array of long integers to be converted
int	nelems			# number of elements in the array
long	max_plusint		# 0 <= b[i] <= max_plusint - 1
long	twice_max_plusint	# twice max_plusint

int	i

begin
	for (i = 1; i <= nelems; i = i + 1) {
	    if (b[i] >= max_plusint)
		b[i] = b[i] - twice_max_plusint
	}
end

Source Code · Search Form · STSDAS