[mod.sources] v08i100: ANSI tape program, Part02/02

sources-request@mirror.UUCP (03/04/87)

Submitted by: David S. Hayes <sundc!hqda-ai!merlin>
Mod.sources: Volume 8, Issue 100
Archive-name: ansitape/Part02

     This is the second part of Ansitape.  It contains the makefile,
the manual pages, and miscellaneous small files.  The program itself is
contained in the first message.

[  I left this in its original wrapper because it wouldn't fit in
   one piece, so I didn't tamper... --r$  ]

#!/bin/sh
# This is a shell archive.  Remove anything before this line, then
# unpack it by saving it in a file and typing "sh file".  (Files
# unpacked will be owned by you and have default permissions.)
#
# This archive contains:
# Makefile ansitape.h tables.c ansitape.1 ansitape.5.tbl
echo x - Makefile
cat > "Makefile" << '//E*O*F Makefile//'
# Makefile for ANSITAPE
#
# This program creates, reads, writes, and takes directory listings of
# ANSI-formatted tapes. 
#
# This program was developed at 
#
# HQDA Army Artificial Intelligence Center
# Pentagon Attn: DACS-DMA
# Washington, DC  20310-0200 
#
# Phone: (202) 694-6900
# E-mail:
#	Arpa:		merlin%hqda-ai.uucp@smoke.brl.arpa
#		alternate	dshayes@smoke.brl.arpa
#	UUCP:		...!seismo!sundc!hqda-ai!merlin
#
# Support?  You want support?  What do I look like, a software house?
# Mail me your gripes, comments, and bugs, and I'll try to keep
# up with them.
#
# THIS PROGRAM IS IN THE PUBLIC DOMAIN.



# Define AT MOST ONE of the following
# Define this if you want debugging.
#CCOPT	= -g
# Define this if you want compiler optimizations.
CCOPT	= -O


# Define this if you want to handle IBM EBCDIC tapes.
IBM	= -DEBCDIC


# Define this to be the maximum size of a file you are willing to
# read to determine the record length.  Files smaller than this
# are read twice:  once to find the max record length, and the second
# time when writing the tape.  Files larger than this just assume
# that the recordlength == blocklength.  Probably not a great
# assumption, but we have to assume something.
#
# If this is not defined, the ansitape.c uses 100K by default.
#READMAX	= 100000


# This is the directory where ansitape will go.
BIN	= /usr/local/bin


# This is the directory where you put your
# unformatted manual pages for commands.
CMDMAN	= /usr/man/man1

# This is the directory where you put your
# unformatted manual pages for file formats.
FILEMAN	= /usr/man/man5

# This is the directory where you put your
# FORMATTED manual pages for file formats.
# Define this to be /tmp if you don't keep
# formatted copies of the file format manual pages.
# Cron should clean it out eventually.
FILECAT	= /usr/man/cat5


all: ansitape man

ansitape: ansitape.c ansitape.h tables.o
	cc ${CCOPT} -o ansitape ${IBM} ${READMAX} ansitape.c tables.o
	mv ansitape ${BIN}

tables.o: tables.c

man: man1 man5

man1: ansitape.1
	cp ansitape.1 ${CMDMAN}

man5: ansitape.5.tbl
	tbl ansitape.5.tbl > ${FILEMAN}/ansitape.5
	tbl ansitape.5.tbl | nroff -man | colcrt > ${FILECAT}/ansitape.5
//E*O*F Makefile//

echo x - ansitape.h
cat > "ansitape.h" << '//E*O*F ansitape.h//'

/*
 * This file contains the definitions of the tape control records. This
 * is to be used when developing a program to work with ANSI standard
 * labelled tapes. 
 */

/*
 * Actually, these should be upper case.  The ansitape program doesn't
 * convert things to upper case until the headers are made -- the tape
 * control block has everything in lower case.  For the sake of easy
 * comparisons, we define them here as lower case. 
 */

#define NOPROTECT ' '		/* space if no protection */
#define REC_FIXED 'f'		/* Records are all fixed length */
#define REC_VARIABLE 'd'	/* Records are preceeded by a 4-digit
				 * zero-filled count of their length,
				 * including the 4 digits themselves */
#define IBM_VARIABLE 'v'	/* IBM's version of ANSI D format */
#define CC_FORTRAN 'a'		/* First char of rec is f-77 carriage
				 * control */
#define CC_EMBEDDED 'm'		/* Carriage control is part of the data
				 * contained in each record */
#define CC_IMPLIED ' '		/* Each record goes on a separate line
				 * when printed */

/*
 * VOLUME 1 Describes the owner of and access to the volume. 
 */

struct ansi_vol1 {
    char            header[4];	/* VOL1 */
    char            label[6];	/* volume name, A-Z0-9 */
    char            access;	/* access code */
    char            __ignored1[20];	/* reserved, space fill */
    char            __ignored2[6];	/* reserved, space fill */
    char            owner[14];	/* user name */
    char            __ignored3[28];	/* reserved, space fill */
    char            ansi_level;	/* ansi standard level, always 3 */
};

/*
 * VOLUME 2 optional, ignored by this software. 
 */

/*
 * HEADER 1 Begins basic description of a tape file. 
 */

struct ansi_hdr1 {
    char            header[4];	/* HDR1 */
    char            name[17];	/* rightmost 17 characters of filename */
    char            fileset[6];	/* should be same as volume id of 1st
				 * tape */
    char            volume_num[4];	/* number of volume in set */
    char            file_num[4];/* number of file on tape */
    char            gen[4];	/* generation number */
    char            genver[2];	/* generation version number */
    char            created[6];	/* date of creation, "bYYDDD" */
    char            expires[6];	/* expiration date "bYYDDD" */
    char            access;	/* protection, space = unprotected */
    char            blockcount[6];	/* zero in header */
    char            tapesys[13];/* name of software creating tape */
    char            __ignored[7];	/* reserved, space fill */
};

/*
 * HEADER 2 Record format, record size, block size. 
 */

struct ansi_hdr2 {
    char            header[4];	/* HDR2 */
    char            recfmt;	/* record format */
    char            blocklen[5];/* file tape block length */
    char            reclen[5];	/* file logical record length */
    char            density;	/* density/recording mode. Should be 2
				 * for 800 bpi, 3 for 1600 bpi. */
    char            vol_switch;	/* 0, or 1 if this file was continued */
    char            job[17];	/* job name (8), /, job step (8) of
				 * creator */
    char            recording[2];	/* parity/conversion, space
					 * fill */
    char            carriage_control;
    char            alignment;	/* reserved, space fill */
    char            blocked_records;	/* 'B' if records are blocked */
    char            __ignored2[11];
    char            block_offset[2];	/* ingore 1st n char of each
					 * block */
    char            __ignored3[28];
};

/*
 * HEADER 3 This contains a bunch of rms-dependent data.  We will
 * ignore it for now, and hope that it doesnt screw up VMS too badly. 
 */

struct ansi_hdr3 {
    char            header[4];	/* HDR3 */
    char            os_reserved[76];	/* reserved to OS, space fill */
};

/*
 * HEADER 4 This is the rest of the filename if its longer than 17
 * characters.  We should have no trouble fitting UNIX filenames into
 * this. 
 */

struct ansi_hdr4 {
    char            header[4];	/* HDR4 */
    char            name2[63];	/* leftmost char, if name is more than
				 * 17 characters long. */
    char            unknown[2];	/* fill with 00 */
    char            __ignored[11];
};


/*
 * FORMAT NOTES 
 *
 * 1.  The tape always starts with a VOL1 record.  Other volume records
 * are optional.  We ignore them, and do not generate them on output. 
 *
 * 2.  Each file starts with a set of HDRn records.  The headers are
 * followed by a tape mark. 
 *
 * 3.  The data is written to the tape in fixed-length blocks.  Valid ANSI
 * block lengths are 18 to 2048 bytes, although VMS will support longer
 * blocks. The block does not have to be full.  If the block is not
 * completely filled, the remainder of the block is padded with
 * circumflex (^) characters.  The file is followed by a tape mark. 
 *
 * 4.  Trailing records are written.  Either EOF or EOV records may be
 * used. The record formats are the same as the HDR records, expect: 
 *
 * a. the "HDR" is replaced by "EOF" or "EOV". 
 *
 * b. the blockcount field in EOF1/EOV1 contains the actual number of
 * physical tape blocks written in the preceding file section.  In the
 * HDR1 record, the blockcount is 000000. 
 *
 * 5.  A tape file may extend across a volume boundary.  If it does, EOV
 * labels are used, indicating that another tape must be read.  If the
 * file ends here, an EOF label is used. 
 *
 * 6.  After the EOF records, a tape mark is written.  This separates the
 * trailers from the headers for the next file.  At the end of the
 * tape, two tape marks are written. 
 */
//E*O*F ansitape.h//

echo x - tables.c
cat > "tables.c" << '//E*O*F tables.c//'
/* Mapping of EBCDIC codes to ASCII equivalents. */
static char     to_ascii_table[256] = {
				       '\000', '\001', '\002', '\003',
				       '\234', '\011', '\206', '\177',
				       '\227', '\215', '\216', '\013',
				       '\014', '\015', '\016', '\017',
				       '\020', '\021', '\022', '\023',
				       '\235', '\205', '\010', '\207',
				       '\030', '\031', '\222', '\217',
				       '\034', '\035', '\036', '\037',
				       '\200', '\201', '\202', '\203',
				       '\204', '\012', '\027', '\033',
				       '\210', '\211', '\212', '\213',
				       '\214', '\005', '\006', '\007',
				       '\220', '\221', '\026', '\223',
				       '\224', '\225', '\226', '\004',
				       '\230', '\231', '\232', '\233',
				       '\024', '\025', '\236', '\032',
				       '\040', '\240', '\241', '\242',
				       '\243', '\244', '\245', '\246',
				       '\247', '\250', '\133', '\056',
				       '\074', '\050', '\053', '\041',
				       '\046', '\251', '\252', '\253',
				       '\254', '\255', '\256', '\257',
				       '\260', '\261', '\135', '\044',
				       '\052', '\051', '\073', '\136',
				       '\055', '\057', '\262', '\263',
				       '\264', '\265', '\266', '\267',
				       '\270', '\271', '\174', '\054',
				       '\045', '\137', '\076', '\077',
				       '\272', '\273', '\274', '\275',
				       '\276', '\277', '\300', '\301',
				       '\302', '\140', '\072', '\043',
				       '\100', '\047', '\075', '\042',
				       '\303', '\141', '\142', '\143',
				       '\144', '\145', '\146', '\147',
				       '\150', '\151', '\304', '\305',
				       '\306', '\307', '\310', '\311',
				       '\312', '\152', '\153', '\154',
				       '\155', '\156', '\157', '\160',
				       '\161', '\162', '\313', '\314',
				       '\315', '\316', '\317', '\320',
				       '\321', '\176', '\163', '\164',
				       '\165', '\166', '\167', '\170',
				       '\171', '\172', '\322', '\323',
				       '\324', '\325', '\326', '\327',
				       '\330', '\331', '\332', '\333',
				       '\334', '\335', '\336', '\337',
				       '\340', '\341', '\342', '\343',
				       '\344', '\345', '\346', '\347',
				       '\173', '\101', '\102', '\103',
				       '\104', '\105', '\106', '\107',
				       '\110', '\111', '\350', '\351',
				       '\352', '\353', '\354', '\355',
				       '\175', '\112', '\113', '\114',
				       '\115', '\116', '\117', '\120',
				       '\121', '\122', '\356', '\357',
				       '\360', '\361', '\362', '\363',
				       '\134', '\237', '\123', '\124',
				       '\125', '\126', '\127', '\130',
				       '\131', '\132', '\364', '\365',
				       '\366', '\367', '\370', '\371',
				       '\060', '\061', '\062', '\063',
				       '\064', '\065', '\066', '\067',
				       '\070', '\071', '\372', '\373',
				       '\374', '\375', '\376', '\377'
};


/* Mapping of ASCII codes to EBCDIC equivalents. */
static char     to_ebcdic_table[256] = {
					'\000', '\001', '\002', '\003',
					'\067', '\055', '\056', '\057',
					'\026', '\005', '\045', '\013',
					'\014', '\015', '\016', '\017',
					'\020', '\021', '\022', '\023',
					'\074', '\075', '\062', '\046',
					'\030', '\031', '\077', '\047',
					'\034', '\035', '\036', '\037',
					'\100', '\117', '\177', '\173',
					'\133', '\154', '\120', '\175',
					'\115', '\135', '\134', '\116',
					'\153', '\140', '\113', '\141',
					'\360', '\361', '\362', '\363',
					'\364', '\365', '\366', '\367',
					'\370', '\371', '\172', '\136',
					'\114', '\176', '\156', '\157',
					'\174', '\301', '\302', '\303',
					'\304', '\305', '\306', '\307',
					'\310', '\311', '\321', '\322',
					'\323', '\324', '\325', '\326',
					'\327', '\330', '\331', '\342',
					'\343', '\344', '\345', '\346',
					'\347', '\350', '\351', '\112',
					'\340', '\132', '\137', '\155',
					'\171', '\201', '\202', '\203',
					'\204', '\205', '\206', '\207',
					'\210', '\211', '\221', '\222',
					'\223', '\224', '\225', '\226',
					'\227', '\230', '\231', '\242',
					'\243', '\244', '\245', '\246',
					'\247', '\250', '\251', '\300',
					'\152', '\320', '\241', '\007',
					'\040', '\041', '\042', '\043',
					'\044', '\025', '\006', '\027',
					'\050', '\051', '\052', '\053',
					'\054', '\011', '\012', '\033',
					'\060', '\061', '\032', '\063',
					'\064', '\065', '\066', '\010',
					'\070', '\071', '\072', '\073',
					'\004', '\024', '\076', '\341',
					'\101', '\102', '\103', '\104',
					'\105', '\106', '\107', '\110',
					'\111', '\121', '\122', '\123',
					'\124', '\125', '\126', '\127',
					'\130', '\131', '\142', '\143',
					'\144', '\145', '\146', '\147',
					'\150', '\151', '\160', '\161',
					'\162', '\163', '\164', '\165',
					'\166', '\167', '\170', '\200',
					'\212', '\213', '\214', '\215',
					'\216', '\217', '\220', '\232',
					'\233', '\234', '\235', '\236',
					'\237', '\240', '\252', '\253',
					'\254', '\255', '\256', '\257',
					'\260', '\261', '\262', '\263',
					'\264', '\265', '\266', '\267',
					'\270', '\271', '\272', '\273',
					'\274', '\275', '\276', '\277',
					'\312', '\313', '\314', '\315',
					'\316', '\317', '\332', '\333',
					'\334', '\335', '\336', '\337',
					'\352', '\353', '\354', '\355',
					'\356', '\357', '\372', '\373',
					'\374', '\375', '\376', '\377'
};


to_ebcdic(source, dest, count)
    char           *source,
                   *dest;
    int             count;
{
    for (; count--;)
	*(dest++) = to_ebcdic_table[0377 & *(source++)];
}


to_ascii(source, dest, count)
    char           *source,
                   *dest;
    int             count;
{
    for (; count--;)
	*(dest++) = to_ascii_table[0377 & *(source++)];
}
//E*O*F tables.c//

echo x - ansitape.1
cat > "ansitape.1" << '//E*O*F ansitape.1//'
.TH ANSITAPE 1 "23 June 1986" AICenter Merlin
.\"@(#)ansitape.1 2.0 86/07/08 AICenter; by David S. Hayes
.SH NAME
ansitape \- ANSI-standard magtape label program
.SH SYNOPSIS
\fIansitape \fPtxrc\[vqfaei3\]
\[\mt=\fIdevice\fP\]
.RS +0.5i
.br
\[vo=\fIvolume-name\fP\]
\[rs=\[ r | \fIrecordsize\fP \]\]
\[bs=\fIblocksize\fP]
.br
\[rf=\[ v | f \]\]
\[cc=\[ i | f | e \]\]
.br
\fIfilename1 filename2\fR . . .
.RE -0.5i
.SH DESCRIPTION
.LP
\fIAnsitape\fP reads, writes, and creates magtapes conforming to
the ANSI standard for magtape labelling.  Primarily, this is useful
to exchange tapes with VAX/VMS, which makes this kind of tape by default.
.LP
\fIAnsitape\fP is controlled by a function key letter
.BR "(t, x, c, or r)" .
Various options modify the format of the output tape.
.SH "Writing ANSI Tapes"
.PP
The list of files on the command line is written to the tape.
A full Unix pathname may be specified, however, only the last
pathname component (everything after the last /) is used as
the filename on the tape.
.PP
Normally, regular text files are to be exchanged.
.I ansitape
reads the files one line at a time and transfers them to the tape.
The newline character at the end of each line is removed, and the
file is written in a variable-length record format.  
Variable-format files have the length of the longest record
specified in a file header.
Therefore,
.I ansitape
will read each input file from disk before it goes on to tape,
to determine the maximum record size.  The read is skipped if
the file is more than 100,000 bytes long.
The default carriage control (implied)
instructs the other host to restore the
newline character before printing the record.
.PP
If \fIansitape\fP thinks that the input file is a Unix text file
(Fortran or implied carriage control), it will automatically strip the
the Unix newline from the end of each record.  No strip is done with
embedded carriage control files, or with any file using a fixed-length
record format.
.PP
For binary files, fixed-length records should be used.  VAX/VMS normally
uses a record length of 512 bytes for things like directories and
executable files, but data files may have any record length.
Binary files should be flagged for embedded (\fIrf=e\fP) carriage
control.
.sp
.SH "Reading ANSI Tapes"
.PP
When reading, the input file list is presumed to be the names
of files to be extracted from the tape.  The shell wildcard
characters asterisk (*) and question-mark (?) may be used.
Of course, they must be quoted to prevent the shell from
interpreting them before
.I ansitape
sees them.
.PP
None of the options for record format or carriage control need
be specified when reading files.
.I Ansitape
will automatically pick up this information from the header
records on the tape, and do the right thing.  If you can't get
just what you want from
.IR ansitape ,
the resulting files may be run through 
.IR dd(1) .
.sp
.SH "FUNCTION LETTERS"
.PP
These function letters describe the overall operation desired.
One of them must be specified in the first argument to
.IR ansitape .
For lexically rigorous Unix fans, a minus sign (-) is allowed,
but optional, to introduce the first keyword option set.
.TP 6
.I r
Write the named files on the end of the tape.  This requires that
the tape have been previously initialized with an ANSI volume header.
.TP 6
.I c
Create a new magtape.  The tape is initialized with a new ANSI volume header.
All files previously on the tape are destroyed.
This option implies \fIr\fP.
.TP 6
.I x
Extract all files from the tape.  Files are placed in the current directory.
Protection is r/w to everyone, modified by the current \fIumask(2)\fP.
.TP 6
.I t
List all of the names on the tape.
.sp
.SH "MODIFIER KEY LETTERS"
.PP
These key letters are part of the first argument to 
.IR ansitape .
.TP 6
.I v
Normally \fIansitape\fP does its work silently; the \fIv\fP (verbose) option 
displays the name of each file \fIansitape\fP treats, preceded by the function
letter.  It also displays the volume name of each tape as it is mounted.
When used with the \fIt\fP option,
\fIansitape\fP displays the number of tape blocks
used by each file, the record format, and the carriage control option.
.TP 6
.I q
Query before writing anything.  On write (c or r options), this
causes \fIansitape\fP to ask before writing to the tape.  On extract
operations, \fIansitape\fP displays the
Unix pathname, and asks if it should extract the file.  Any response
starting with a 'y' or 'Y' means yes, any other response (including
an empty line) means no.
.TP 6
.I f
File I/O is done to standard i/o instead.  For example, when writing a
tape file that is to contain a lint listing, we could specify
.sp
	lint xyz.c | ansitape rf xyz.lint
.sp
instead of
.sp
	lint xyz.c > /tmp/xyz.lint
.br
	ansitape r /tmp/xyz.lint
.br
	rm /tmp/xyz.lint
.sp
When reading, this option causes the extracted files to be sent to
stdout instead of a disk file.
.TP 6
.I a
The tape should be read or written with the ASCII character set.  This
is the default.
.TP 6
.I e
The tape should be written with the EBCDIC character set.  The
mapping is the same one used by the 
.I dd(1)
program with
.IR conv=ebcdic .
This option is automatically enabled if IBM-format labels are selected.
.TP 6
.I i
Use IBM-format tape labels.  The IBM format is very similar, but
not identical, to the ANSI standard.  The major difference is that
the tape will contain no HDR3 or HDR4 records, thus restricting the
name of the files on the tape to 17 characters.  This option automatically
selects the EBCDIC character set for output.  To make an IBM-format
label on a tape using the ASCII character set (why?), use the
option sequence
.IR ia .
.TP 6
.I 3
Do not write HDR3 or HDR4 labels.  The HDR3 label is reserved for
the use of the operating system that created the file.  HDR4 is for
overflow of filenames that are longer than the 17 characters allocated
in the HDR1 label.  Not all systems process these labels correctly, or
even ignore them correctly.  This switch suppresses the HDR3 and HDR4
labels when the tape is to be transfered to a system that would
choke on them.
.SH "FUNCTION MODIFIERS"
.PP
Each of these options should be given as a separate argument to
.IR ansitape .
Multiple options may be specified.  They must appear as after the
key-letter options above, and before any filename arguments.
.TP 6
.IR mt= device
Select an alternate drive on which the tape is mounted.
The default is 
.IR /dev/rmt8 .
.TP 6
.IR vo= volume-name
Specify the name of the output volume.  Normally, this defaults
to the first six characters of your login name.  The string 'UNIX'
is used as the default if \fIansitape\fP cannot determine your login name.
.TP 6
.IR rs= recordsize
Specify the output recordsize in bytes.  This is the maximum size
in the case of variable-format files.  This option also turns on
the fixed-record-format option.  Thus, if you want to have variable
record sizes with a smaller maximum, you must specify
.sp
.ce 
.IR rs= "recordsize " rf=v
.sp
When the recordsize is manually given, 
.I ansitape
does not read disk files to determine the maximum record length.
.TP 6
.I rs=r
This is a variant of the 
.I rs=
option.  This causes 
.I ansitape
to read all disk files for recordsize, regardless of their size.
Normally, files larger than 100K bytes are not scanned for recordsize.
Using this option also implies variable-length records.
.TP 6
.IR bs= blocksize
Specify the output blocksize, in bytes.  As many records as will
fit are crammed into each physical tape block.  ANSI standards
limit this to 2048 bytes (the default), but you may specify more
or less.  Be advised that specifying more may prevent some
systems from reading the tape.
.TP 6
.I rf=v
Record format is variable-length.  In other words, they are
text files.  This is the default, and should be left alone unless
you really know what you're doing.
.TP 6
.I rf=f
Record format is fixed-length.  This is usually
a bad choice, and should be reserved for binary files.  This also
turns off the newline strip usually done for Unix text files.
.TP 6
.I cc=i
Carriage control implied (default).
Unlike Unix text files, where records are delimited by a newline character,
ANSI files do not normally include the newline as part of the record.
Instead, a newline is automatically added to the record whenever it is
sent to a printing device.
.TP 6
.I cc=f
Carriage control Fortran.
Each line is expected to start with a Fortran carriage-control
character.  \fIAnsitape\fP does not insert these characters
automatically, it merely marks the file as having them.
This is of limited usefulness.  (Good opportunity for another
ambitious hacker.)
.TP 6
.I cc=e
Carriage control is embedded.  Carriage control
characters (if any) are a part of the data records.  This is usually used in
the case of binary data files.
.TP 6
.SH FILES
/dev/rmt?	half-inch magnetic tape interface
.br
/dev/rar?	quarter-inch magnetic tape interface
.br
/dev/rst?	SCSI tape interface
.SH "SEE ALSO"
dd(1), umask(2), mtio(4), tp(5)
.SH AUTHOR
David S. Hayes, Site Manager, US Army Artificial Intelligence Center.
Originally developed June 1986.
Revised August 1986.  This software is in the public domain.
.SH BUGS
.LP
The
.I r
(write) option cannot be used with quarter-inch archive tapes,
since these tape drives cannot backspace.
.LP
There is no way to ask for the
.IR n -th
occurrence of a file.
.LP
Tape errors are handled ungracefully.
.LP
Files with names longer than 80 characters have the name truncated.
This is a limitation of the ANSI labelling standard.  If the tape is
made without HDR3 and HDR4 labels (\fI3\fP or \fIi\fP switch), the
name is limited to 17 characters.
.LP
Multi-volume tape sets cannot yet be generated.
.I ansitape
will read them just fine, but it won't write them.
Unix provides no device-independent way to detect
a physical end-of-tape.  It was decided that a 2400-foot
limitation was preferrable to device-dependence.
.TP 6
Note to Systems Programmers:
.I ansitape
uses a boolean function
.I (eot)
to determine when the tape drive
has hit the end of file.  It is called every time a block
of data is written to the tape.  If this function ever returns
TRUE (a defined constant), an automatic volume switch occurs.
The pertinent device registers are obtained by a MTIOCGET
ioctl system call.  The registers are described in
.I /sys/sundev/tmreg.h
(Sun system with TapeMaster controller).  If you
have a VAX, the filename will be slightly different.
Sun Microsystems supplies this file even with binary-only
distributions.
//E*O*F ansitape.1//

echo x - ansitape.5.tbl
cat > "ansitape.5.tbl" << '//E*O*F ansitape.5.tbl//'
.TH ANSITAPE 5  "8 August 1986"
.SH NAME
ansitape - ANSI standard magtape labels
.SH DESCRIPTION
.PP
An ANSI-labelled tape starts with a volume header.
This header specifies the volume name and protection,
the owner of the volume, and the ANSI label standard level
that the tape conforms to.
.PP
Every file on the tape has a header, some data blocks, and
a trailer.  A tape mark follows each of these elements.
At the end of the tape, two tape marks follow the trailer,
to indicate logical end-of-tape.
.PP
If a file is too large to be copied onto one tape, it may
be continued on another tape by modifying the trailer section.
.sp
.SH "VOLUME HEADER"
.TS
expand allbox;
c c c c
l n c l .
Field	Width	Example	Use
VOL1	4	VOL1	T{
Indicates this is a volume header.
T}
Label	6	VAX1	T{
The name of the volume.
T}
Access	1	space	T{
Volume protection.  Space means unprotected.
T}
IGN1	20		<< ignored >>
IGN2	6		<< ignored >>
Owner	14	Joe User	T{
The name of the user.
T}
IGN3	28		<< ignored >>
Level	1	3	ANSI standard level.
.TE
.sp
.TP 10
Owner
The owner field is 14 characters in ANSI labels.
IBM labels cut the owner field to 10 characters.
The IGN2 field is 10 characters on IBM-format tapes.
.bp
.SH "FILE HEADERS"
.LP
.TS
expand allbox;
c c c c
l n c l .
Field	Width	Example	Use
HDR1	4	HDR1	T{
Identifies first file header.
T}
Name	17	FILE.DAT	T{
Leftmost 17 characters of filename.
T}
Set	6	VAX1	T{
Name of volume set this file is part of.
T}
Vol Num	4	0001	T{
Number of this volume within volume set.
T}
File Num	4	0001	T{
Number of file on this tape.
T}
Generation	4	0001	T{
Like a major release number.
T}
Gen Version	2	00	T{
Version of a file within a release.
T}
Created	6	b86001	T{
The date of file creation.
T}
Expires	6	b86365	T{
Date file expires.
T}
Access	1	space	T{
File protection.  Space means unprotected.
T}
Blockcount	6	000000	T{
Number of blocks in the file.
T}
System	13	OS360	T{
The name of the software system
that created the tape.
T}
IGN	7		<< ignored >>
.TE
.sp
.TP 1i
Name
The filename may be up to 17 characters in IBM labels,
and ANSI labels before standard level 3.
On ANSI level 3 and after, the HDR4 record provides
overflow storage for up to 63 more characters of filename.
.TP
Set Name
On multi-reel tape sets, a name identifying the set as a whole.
Normally, this is just the volume name of the first reel in the set.
.TP
Generation
Like a major release number.  The version field is a version
within a generation.  On VAX/VMS systems, these two fields are
mathematically related to the (single) version number of disk files.
.TP
Created
The date the file was created.  This is a six character field,
where the first character is always a space.
The next two are the year.  The final 3 are the day within
the year, counting January 1st as day 1.
.TP
Blocks
The number of blocks in the file.  In HDR1 records, this is
always zero.  The corresponding EOF1 or EOV1 contains the
number of tape blocks written in the file on the current reel.
.bp
.LP
.TS
expand allbox;
c c c c
l n c l .
Field	Width	Example	Use
HDR2	4	HDR2	T{
Second file header.
T}
Rec Format	1	D	Record format.
Blk Length	5	02048	Tape block size.
Rec Length	5	00080	Record size.
Density	1	3	Recording density code.
Vol Switch	1	0	T{
1 if this is a continuation of a file from a previous reel.
T}
Job	17	user/program	See following notes.
Recording	2	space	Unused in 9-track tapes.
Car Control	1	space	See following notes.
Blocking	1	B	See following notes.
IGN	11		<< ignored >>
Offset	2	00	T{
Bytes to skip at front of each block.
T}
.TE
.TP
Rec Format
A single character indicating what type of records are
provided.  The codes are
.sp
.TS
center allbox;
c c
c l .
Code	Meaning
F	Fixed-length
D	Variable up to rec length
V	IBM code for variable
U	Unknown
.TE
.TP
Job
The name of the job (username in Unix) right-padded
to 8 characters, a slash (/), and the job step
(program name in Unix) right-padded to 8 characters.
This identifies where the JCL was when this file
was created.
.TP
Carriage Control
Normally a space, indicating that the records do not
contain carriage control information.  When printed,
each record is placed on a separate line.
If an 'A' is used, the first character of each record
is presumed to be a Fortran carriage-control character.
VAX/VMS also uses 'M' to indicate that carriage-control
is embedded as part of the data.  This is usually used
in the case of binary files.
.TP
Blocking
The B indicates that as many records as will fit are
placed in a physical tape block.  Records do not cross
block boundaries.  A space indicates only one record
per physical tape block.
.bp
.LP
The HDR3 and HDR4 labels are not written on IBM tapes.
ANSI allows, but does not require, these labels.
.sp
.TS
expand allbox;
c c c c
l n c l .
Field	Width	Example	Use
HDR3	4	HDR3	Third file header.
OS	76		Operating-system dependent.
.TE
.TP
OS
This field is reserved for the use of the operating system
that created the file.  Other operating systems are supposed
to disregard HDR3 records.  On VAX/VMS, this record contains
the RMS file description.
.sp
.LP
.TS
expand allbox;
c c c c
l n c l .
Field	Width	Example	Use
HDR4	4	HDR4	Fourth file header.
Name 2	63		Name continuation from HDR1.
Unknown	2	00	Unknown, fill with 00.
IGN	11		<< ignored >>
.TE
.TP
Name 2
On ANSI tapes, if the filename is longer than
17 characters, the first 17 are placed in the HDR1
record.  The next 63 are put in HDR4.  Filenames
longer than 80 characters are truncated.  Note
that it is not required to have a HDR3 record
in order to have a HDR4.
.sp
.SH "FILE TRAILING LABELS"
.PP
These labels are written after a tape file.
For every label written at the head of the file,
there will be a corresponding label at the tail.
Except for the 
.I "block count"
field in HDR1, the only difference is in the name
of the label.
If we have reached the logical end of the file,
the characters 
.I HDR
in the headers are replaced by the characters
.I EOF
in the trailing labels.
If we are not at the logical end of the file, but
are merely pausing at the physical end of tape before
continuing on another reel, the
.I HDR
characters are replaced by
.I EOV
(end-of-volume).
.PP
The
.I "block count"
field of HDR1 was initially recorded as 000000.  When
the trailers are written, the block count is changed
to indicate the number of tape data blocks written.
A file that is continued over several volumes maintains
separate counts for each reel.
.SH "RECORD FORMATS"
.PP
The two basic record formats are fixed and variable.
.PP
Fixed format uses records that are all constant length.  This
is the case with VAX/VMS executable images (record length = 512).
It is also used by IBM systems for text files, with a record length
of 80 (card images).  The record size field of HDR2 tells how long each
record is.
.PP
With fixed-length records, the blocksize is usually selected to
be some multiple of the recordsize.  As many records as will
fit are placed in each block.  Since records do not (normally)
span physical tape blocks, extra space at the end of a block is wasted.
.PP
Variable-length records are used by VAX/VMS for text files.
The Unix program 
.I ansitape(1)
also turns Unix text files into variable-length tape files.
With this format, the record length specified in HDR2 is an
upper limit.
.PP
Each record is preceeded by a 4-digit (zero-filled) byte count.
The count included the digits themselves, so the minimum valid
number is 0004.  These four digits specify how long the record
is.  The data follows the digits, and is in turn followed by
the digits for the next record.
.PP
When writing, 
.I ansitape
checks to make sure that there is enough room in the tape block
for the next record.  If the record (including its length digits)
won't fit, the current block is sent to the tape, and a new
block is started.  Unused space at the end of the tape block is
filled with circumflex (^) characters.
//E*O*F ansitape.5.tbl//

echo Possible errors detected by \'wc\' [hopefully none]:
temp=/tmp/shar$$
trap "rm -f $temp; exit" 0 1 2 3 15
cat > $temp <<\!!!
      83     363    2185 Makefile
     149     881    5555 ansitape.h
     156     578    5687 tables.c
     302    1797   10559 ansitape.1
     290    1477    7890 ansitape.5.tbl
     980    5096   31876 total
!!!
wc  Makefile ansitape.h tables.c ansitape.1 ansitape.5.tbl | sed 's=[^ ]*/==' | diff -b $temp -
exit 0
-- 
	David S. Hayes, The Merlin of Avalon
	PhoneNet:	(202) 694-6900
	ARPA:		merlin%hqda-ai.uucp@brl-smoke
	UUCP:		...!seismo!sundc!hqda-ai!merlin