ansitar, read and write ANSI labeled tapes
mackay at uw-june.UUCP
mackay at uw-june.UUCP
Sun May 20 00:13:23 AEST 1984
# The rest of this file is a shell script which will extract:
# README ansitar.1 ansitar.c
echo x - README
cat >README <<'StopHere'
Ansitar reads from or writes to a magnetic tape in ANSI labeled
tape format, which is a useful format for exchange of ASCII
character files with a non-UNIX system. Eight-bit binary is
also possible, using F-type blocking, but the results are
likely to be unsatisfactory in most cases.
This program was forwarded to me in answer to a desperate request, and
has already proved very useful. It appeared on net.sources earlier
with ANSI System level 1 capacities, and has now acquired System
level 3 capacities (i. e. everything but spanned records). Spanned
records would not be very difficult, but they do not seem to be
very much in demand either.
It reads and writes HDR2 labels as well as HDR1 labels, and is thus
capable of deblocking tapes without explicit declaration of block
or record sizes. A large number of the more interesting features
are still marked off as VARIAN code because that is the way I received the
program. The VARIAN code is basic to efficient operation, unlike the
PIP code, which is for a rather special environment.
I have not bothered to provide a makefile, since there is only one
program here. ansitar.1 belongs ideally in /usr/man/man1 and
the executable program anywhere in a generally used path.
mackay at washington.ARPA (Computer Science, Univ of Washington)
'StopHere'
echo x - ansitar.1
cat >ansitar.1 <<'StopHere'
.TH ANSITAR 1 5/1/84
.SH NAME
ansitar \- read or write ANSI multifile labeled tapes
.SH SYNOPSIS
.B ansitar
subcommand [blocksize] [linesize] [vsn] file
.br
.B ansitar
.RB "subcommand[" "RSl" "]"
[blocksize] [linesize] [labelsize] [vsn] file
.LP
.SH DESCRIPTION
.I Ansitar
reads from or writes to a magnetic tape in ANSI labeled
tape format, which is a
useful format for exchange of ASCII character files
with a non-UNIX system. Eight-bit binary is also possible,
but the results are likely to be unsatisfactory in most
cases.
.PP
A non-standard version compiled with
.B #define PIP
permits reading of RT11 and RSTS files as well.
.PP
.I subcommand
is any rational concatenation of compatible characters from
the following groups \- only one from each group:
.IP
.B [crtx], [bBDF], [RS],
.B l, U, v, V, [0..9]
.LP
.TP
.B c
Create a new multifile tape. (Destroy all previous files on tape).
.TP
.B r
Replace files on tape without destroying any previous files.
.TP
.B t
List all files on tape.
.TP
.B x
Extract files from tape. (See note on `*' wild-card character).
.TP
.B b
Use next argument as a tape block size.
.TP
.B B
Use next argument as a tape block size and following argument as
line size (for blocking/unblocking of fixed length records).
.TP
.B D
.I Reading.
Not required for System level 3 tape with valid HDR2 label.
For System level 1 and 2 use next argument as tape block size.
.I Writing.
Write HDR2/EOF2 labels and variable
length records (D format, System level 3) with block size
2048 and maximum line size 255.
.TP
.B F
.I Reading.
Not required if tape has valid HDR2 label. Use
.B B
for ANSI System level 1 tapes.
.I Writing.
Same as B, but write HDR2/EOF2 label for
automatic unblocking. (F format, System level 3).
.TP
.B R
Read with RT11 label and name conventions.
.TP
.B S
Read with RSTS conventions (same as RT11,
except 80-character labels).
.TP
.B l
Use next argument as non-standard label size.
.TP
.B U
Do case conversion on alphabetic characters in filenames.
Upper-case to lower-case from tape to UNIX. Lower-case
to upper-case from UNIX to tape.
.TP
.B v
Use
.I `verbose'
mode \- Lots of information about labels.
.TP
.B V
Use next argument (up to 6 alphanumeric characters) as tape
.I vsn.
.TP
.B 1..9
Select tape unit (default is
.I /dev/rmt8
).
.PP
The arguments for
.B b, B, D, F, l
are unsigned decimal strings. It is probably preferable
to use only upper-case alphabetics in the argument to
.B V.
Arguments are evaluated in the order in which the associated
subcommand characters appear.
.PP
Note: The `*' wild card character may be used to get a number
of related files from tape, but in that case the filename
must be quoted to prevent the shell from attempting to
expand the wild card. When writing from UNIX to tape,
wild cards work normally.
.SH SEE ALSO
.I ANSI X3.27-1978:
Magnetic Tape Labels and File Structure for Information Interchange.
.br
.I ISO 1001-1979:
Magnetic Tape Labels and File Structure for Information Interchange.
.SH AUTHORS
Unknown, modified by David R. Brown, further
modified by Pierre A. MacKay.
.SH BUGS
'StopHere'
echo x - ansitar.c
cat >ansitar.c <<'StopHere'
/*
>From zehntel!ihnp4!ixn5c!inuxc!pur-ee!uiucdcs!uiucuxc!root Sat Jul 2 04:31:32 1983
Subject: Ansitar.c - (nf)
Newsgroups: net.sources
#N:uiucuxc:12500005:000:19678
uiucuxc!root Jul 1 23:55:00 1983
*
* 10/28/83 DRB: new option 'D': read variable length records (D format)
* 10/29/83 FGH: 1. wildcard ability added to filenames.
* 2. when output filename isn't valid for Unix (as it's perhaps
* taken from a foreign tape), this program now just skips
* that file rather than exiting the whole job.
* 10/30/83 FGH: 1. some problems with varunblock's handling of end of record.
* still must use 'D' option with 'b' such that b's argument
* exceeds the tape's physical record size (2048 in my case)
* 2. changed varunblock/doxtract to correct the byte count.
*
* 10/31/83 DRB:
* new option P - create/read files in "pip" (FILES-11) counted format.
* handle tape read error
* From zehntel!tektronix!ucbcad!ucbvax!decvax!microsoft!uw-beaver!cornell!vax135!floyd!harpo!utah-cs!utah-gr!thomas Tue Aug 2 21:27:08 1983
* (=Spencer) (#ifdef PIP)
# MACKAY at WASHINGTON.ARPA
* 04/24/84 PAM:
* 1. Upgrade to ANSI X3.27 System level 3.
* Program now reads and writes HDR2 label
* for deblocking info.
* 2. When reading, sets blocksize only if D-type, blocksize
* and linesize (aka record-length) if F-type.
* Neither D nor b/B need be specified on the
* command line if tape has valid HDR2 labels.
* 3. Full HDR2 info provided in "verbose mode."
* (Ought to check matching EOF2 and print string
* for HDR3-9/EOF3-9 labels)
* 4. If D is used as an option in writing, a default
* blocksize of 2048 is chosen, based on the ISO
* recommendation for maximum blocksize. Line length
* is limited to 255 bytes, which seems a reasonable
* maximum.
*
*/
#define VARIAN
#define PIP
#ifdef VARIAN
#define DEBUG 0 /* set to nonzero to debug new Varian code */
#define DBG if(DEBUG) fprintf(stderr,
#define WILDCARD '*'
#endif VARIAN
#include <stdio.h>
#include <ctype.h>
#include <time.h>
#include <pwd.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/mtio.h>
/* ansitar -- archiver for ansi-format labelled tapes
*
* ansitar [crxtvbl] [blocksize] [labelsize] file ...
*
* The options are similar to tar:
* c - create a tape
* r - replace (update) a tape
* x - extract files
* t - print table of contents
* v - set verbose mode: for crx, print names; for t print labels
* 0-9 - select drive 0-9
* b - use next argument as a block size
* B - use next argument as tape block size, and
* following argument as line size (for blocking/unblocking)
* l - use next arg as a label size
* U - select upper(out)/lower(in) case translation of names
* V - use next argument as a VSN
* R - use RT11 label and name conventions (UGH!)
* S - use RSTS conventions (==RT11 except 80-byte labels)
* P - create/read files in "pip" (FILES-11) counted format.
* D - create/read files with variable length records (D format)
*
* When extracting from tape to UNIX, the filename may contain * to
* indicate a wild card; however, the asterisk should be enclosed
* in quotes, however, to prevent the shell from interpreting it.
*
* Examples of usage:
* ansitar tv Verbose table of contents
* ansitar xvDUb 2000 file1 file2 Extract file1 and file2 from
* tape with 2000 bytes/block
* and variable length records
*
* BUGS:
*
* Warning: The routines skipfile and backspace use nonstandard
* (4.1BSD) ioctl calls!
*/
#define Skiparg() argc--; argv++
#define MAXLINE 256
#define TRUE 1
#define FALSE 0
#define READ 0
#define READWRITE 2
#define ISOBLOCK 2048
/* field sizes */
#define LABID 3
#define SERIAL 6
#define OWNER 14
#define FILEID 17
#define SETID 6
#define SECNO 4
#define SEQNO 4
#define GENNO 4
#define GENVSNO 2
#define CRDATE 6
#define EXDATE 6
#define BLOCKS 6
#define SYSTEM 13
#define BLKMAX 5
#define RECMAX 5
#define BYTOFFS 2
#define DBYTES 4
/* pad fields (reserved for future use) */
#define VRES1 20
#define VRES2 6
#define VRES3 28
#define HRES1 7
#define H2RES1 35
#define H2RES2 28
/* Volume header label */
struct vol {
char v_labid[LABID]; /* label identifier "VOL" */
char v_labno; /* label number */
char v_serial[SERIAL]; /* volume serial number */
char v_access; /* accessibility */
char v_res1[VRES1]; /* reserved for future use */
char v_res2[VRES2]; /* reserved for future use */
char v_owner[OWNER]; /* owner identifier */
char v_res3[VRES3]; /* reserved for future use */
char v_stdlabel; /* standard label flag */
};
/* file header/eof label */
struct hdr {
char h_labid[LABID]; /* label identifier: "HDR" or "EOF" */
char h_labno; /* label number */
char h_fileid[FILEID]; /* file identifier */
char h_setid[SETID]; /* file set identifier */
char h_secno[SECNO]; /* file section number */
char h_seqno[SEQNO]; /* file sequence number */
char h_genno[GENNO]; /* generation number */
char h_genvsno[GENVSNO]; /* generation vsn number */
char h_crdate[CRDATE]; /* creation date */
char h_exdate[EXDATE]; /* expiration date */
char h_access; /* accessibility */
char h_blocks[BLOCKS]; /* block count */
char h_system[SYSTEM]; /* system code */
char h_x1[7]; /* reserved */
};
/* deblocking hdr2/eof2 label */
struct hd2 {
char h2_labid[LABID]; /* label identifier: "HDR" or "EOF" */
char h2_labno; /* label number "2" */
char h2_datatype; /* type identifier "D" or "F" */
char h2_blkmax[BLKMAX]; /* maximum block size in bytes */
char h2_recmax[RECMAX]; /* maximum record size in bytes */
char h2_x1[H2RES1]; /* reserved */
char h2_bytoffs[BYTOFFS]; /* extra stuff at start of block */
char h2_x2[H2RES2]; /* reserved */
};
struct vol vol1;
struct hdr hdr1, eof1;
struct hd2 hdr2, eof2;
char *tapefile = "/dev/rmt8";
char *buffer, *linebuffer, *malloc(), *realloc(), *index();
char **filetab;
unsigned blocksize = 512;
unsigned linesize = 0;
int bfactor = 0;
int labelsize = sizeof(struct vol);
int tapeunit = 0;
int tf;
char *defvsn = "";
char curdate[CRDATE+1];
char *alongtime = " 99364";
#ifdef PIP
int create, replace, xtract, table, verbose, confirm, pipfile;
#else
int create, replace, xtract, table, verbose, confirm;
#endif
int blocking;
int RT11, Upper;
#ifdef VARIAN
int Varlen;
#endif VARIAN
int Fixlen;
main(argc, argv)
int argc;
char **argv;
{
char *ap;
int bufsize, openmode;
if (argc < 2)
usage();
Skiparg();
openmode = READ;
ap = argv[0];
Skiparg();
while (*ap) {
switch (*ap) {
case 'c':
create++;
openmode = READWRITE;
break;
case 'r':
replace++;
openmode = READWRITE;
break;
case 'x':
xtract++;
break;
case 't':
table++;
break;
case 'v':
verbose++;
break;
case 'w':
confirm++;
break;
case 'b':
case 'B':
case 'F':
blocking++;
blocksize = atoi(argv[0]);
if (blocksize <= 0)
fatal("bad block size %s\n", argv[0]);
Skiparg();
if ((*ap == 'B') || (*ap == 'F')) {
linesize = atoi(argv[0]);
if (linesize <= 0 ||
blocksize % linesize != 0)
fatal("bad line size %s\n", argv[0]);
bfactor = blocksize / linesize;
Skiparg();
}
if (*ap == 'F') Fixlen++;
break;
case 'l':
labelsize = atoi(argv[0]);
if (labelsize < sizeof(struct hdr))
fatal("label size must be >= %d\n",
sizeof(struct hdr));
Skiparg();
break;
case 'U':
Upper++;
break;
case 'V':
defvsn = argv[0];
if (strlen(defvsn) > SERIAL)
defvsn[SERIAL] = '\0';
Skiparg();
break;
case 'S':
case 'R':
RT11++;
Upper++;
if (*ap == 'R')
labelsize = 512;
break;
#ifdef VARIAN
case 'D':
Varlen++;
break;
#endif VARIAN
#ifdef PIP
case 'P':
pipfile++;
break;
#endif PIP
default:
if (isdigit(*ap)) {
tapeunit = *ap;
break;
}
fatal("bad flag: %c\n", *ap);
}
ap++;
}
filetab = argv;
filetab[argc] = NULL;
if (tapeunit)
tapefile[strlen(tapefile)-1] = tapeunit;
tf = open(tapefile, openmode);
if (tf < 0)
fatal("can't open %s%s\n", tapefile,
(openmode != READ) ? " for writing" : "");
bufsize = max(blocksize, labelsize);
buffer = malloc(bufsize + 10);
if (buffer == NULL)
fatal("can't allocate buffer of %d bytes\n", blocksize);
if (linesize) {
linebuffer = malloc(linesize + 10);
if (linebuffer == NULL)
fatal("can't allocate line buffer of %d bytes\n",
linesize);
}
getansidate(curdate);
if (verbose && blocking) {
printf("Blocksize: %d", blocksize);
if (linesize)
printf(" Linesize: %d", linesize);
putc('\n', stdout);
}
if (create || replace)
doupdate(tf);
else if (xtract)
doxtract(tf);
else if (table)
dotable(tf);
else
usage();
exit(0);
}
usage()
{
fatal("usage: ansitar crxtvbl [blocksize] [labelsize] file ...\n");
}
dotable(tf)
int tf;
{
char fileid[FILEID+1];
int files, n;
int blocks;
int lbseq;
long bytes;
getvol(tf, &vol1);
prtvol(&vol1);
putc('\n', stdout);
files = 0;
lbseq = '1';
while (gethdr(tf, &hdr1)) {
files++;
if (verbose)
prthdr(&hdr1);
getmark(tf, &hdr2, lbseq);
sncpy(fileid, hdr1.h_fileid, FILEID);
blocks = 0;
bytes = 0L;
while ((n = getrec(tf, buffer, blocksize)) > 0) {
blocks++;
bytes += n;
}
lbseq = '1';
geteof(tf, &eof1);
if (verbose)
prthdr(&eof1);
getmark(tf, &hdr2, lbseq);
cmphdreof(&hdr1, &eof1);
if (verbose)
putc('\n', stdout);
printf("t %s %d blocks %D bytes\n", fileid, blocks, bytes);
if (linesize)
printf("\t F-type: blocksize: %d linesize %d\n", blocksize, linesize);
else
printf("\t D-type: blocksize: %d\n", blocksize);
if (verbose)
putc('\n', stdout);
}
printf("\n%d files\n", files);
}
doxtract(tf)
int tf;
{
char fileid[FILEID+1];
FILE *fp;
long bytes;
int blocks;
int n, xall;
int lbseq;
#ifdef VARIAN
int newn;
#endif VARIAN
lbseq = '1';
xall = (filetab[0] == NULL);
getvol(tf, &vol1);
if (verbose)
prtvol(&vol1);
while (gethdr(tf, &hdr1)) {
getmark(tf, &hdr2, lbseq);
sncpy(fileid, hdr1.h_fileid, FILEID);
trimsp(fileid);
if (RT11)
fromRT11(fileid);
/* if 1.you're doing all the files or 2. this file matches */
/* one of the the names in the arglist, then copy it, else */
/* skip this file. filetab is really 'argv' list. */
if ( (xall || lookup(filetab, fileid, Upper)) &&
checkw('x', fileid) ) {
if (Upper) makelower(fileid); /* name to lower case*/
fp = fopen(fileid, "w");
#ifdef VARIAN
if (fp == NULL)
{
printf("can't create %s - will skip\n", fileid);
skipfile(tf);
}
#else
if (fp == NULL) fatal("can't create %s\n", fileid);
#endif VARIAN
else{ /* file OK, do the copy */
blocks = 0;
bytes = 0L;
while ((n = getrec(tf, buffer, blocksize)) > 0) {
if (linesize)
lunblock(fp, buffer, n, linesize);
else
#ifdef VARIAN
if (Varlen)
{
newn = varunblock(fp,buffer,n);
n = newn; /* now it's # written */
}
else
#endif VARIAN
#ifdef PIP
if (pipfile)
pipunblock(fp, buffer, n);
else
#endif PIP
fwrite(buffer, n, 1, fp);
blocks++;
bytes += n;
}
fclose(fp);
if (verbose)
printf("x %s %d blocks %D bytes\n",
fileid, blocks, bytes);
} /* end 'if file open was OK' */
} /* end 'if filename OK or copying all' */
else /* if this file is not be copied */
skipfile(tf);
lbseq = '1';
geteof(tf, &eof1);
cmphdreof(&hdr1, &eof1);
getmark(tf, &hdr2, lbseq);
}
}
doupdate(tf)
int tf;
{
int i, n;
int blocks;
long bytes;
char line[MAXLINE];
char fileid[FILEID+1];
char recmax[RECMAX+1];
FILE *fp;
int sequence;
int lbseq;
lbseq = '1';
sequence = 0;
if (create) {
initvol(&vol1);
putvol(tf, &vol1);
}
else { /* replace */
getvol(tf, &vol1);
while (gethdr(tf, &hdr1)) {
sncpy(line, hdr1.h_seqno, SEQNO);
sequence = atoi(line);
getmark(tf, &hdr2, lbseq);
skipfile(tf);
lbseq = '1';
geteof(tf, &eof1);
getmark(tf, &hdr2, lbseq);
}
backspace(tf);
}
for (i=0; filetab[i] != NULL; i++) {
if (!checkw('a', filetab[i]))
continue;
strncpy(fileid, filetab[i], FILEID);
fileid[FILEID] = '\0';
fp = fopen(fileid, "r");
if (fp == NULL)
fatal("can't open %s\n", fileid);
sequence++;
if (RT11)
toRT11(fileid);
if (Upper)
makeupper(fileid);
inithdr(&hdr1, fileid, sequence);
puthdr(tf, &hdr1);
if (Varlen) {
blocksize = ISOBLOCK;
realloc(buffer,blocksize+10);
linesize = 0;
inithdr2(&hdr2, 'D', blocksize, 0);
n = dblock(fp, buffer, blocksize);
utoaz(n, recmax, RECMAX);
blcopy(hdr2.h2_recmax, recmax, RECMAX);
puthdr(tf, &hdr2);
fclose(fp);
fp = fopen("#tmp.tmp", "r");
if (fp == NULL) fatal("can't re-read #tmp.tmp\n");
}
if (Fixlen) {
inithdr2(&hdr2, 'F', blocksize, linesize);
puthdr(tf, &hdr2);
}
tapemark(tf);
blocks = 0;
bytes = 0L;
if (linesize)
while ((n = lblock(fp, buffer, linesize, bfactor)) > 0) {
if (n % 2) {
buffer[n] = '\0';
n++;
}
n = write(tf, buffer, n);
blocks++;
bytes += n;
}
#ifdef PIP
else if (pipfile)
while ((n = pipblock(fp, buffer, blocksize)) > 0)
{
n = write(tf, buffer, n);
blocks++;
bytes += n;
}
else
#else
else
#endif PIP
while ((n = fread(buffer, sizeof(char), blocksize, fp)) > 0) {
if (n % 2) {
buffer[n] = '\0';
n++;
}
n = write(tf, buffer, n);
blocks++;
bytes += n;
}
fclose(fp);
tapemark(tf);
blcopy(hdr1.h_labid, "EOF", LABID);
utoaz(blocks, line, BLOCKS);
blcopy(hdr1.h_blocks, line, BLOCKS);
puthdr(tf, &hdr1);
if ((Varlen) || (Fixlen)) {
blcopy(hdr2.h2_labid, "EOF", LABID);
puthdr(tf, &hdr2);
}
tapemark(tf);
if (verbose)
printf("a %s %d blocks %D bytes\n",
fileid, blocks, bytes);
}
tapemark(tf);
}
getvol(tf, volp)
int tf;
struct vol *volp;
{
int n;
if (labelsize == sizeof(struct vol))
n = read(tf, (char *)volp, sizeof(struct vol));
else {
n = read(tf, buffer, labelsize);
bcopy((char *)volp, buffer, sizeof(struct vol));
}
#ifdef PIP
if (n<0)
{
perror("Tape read error");
exit(1);
}
#endif PIP
if (n != labelsize ||
strncmp(volp->v_labid, "VOL", LABID) != 0 ||
volp->v_labno != '1') {
printf("Warning: Volume label (VOL1) missing\n");
backspace(tf);
return;
}
/* check for RT11 boot block between VOL1 and first HDR1 */
if (RT11) {
/* must have labelsize = 512 */
n = read(tf, buffer, labelsize);
bcopy((char *)&hdr1, buffer, sizeof(struct hdr));
if (n == labelsize && strncmp(hdr1.h_labid, "HDR", LABID) == 0)
backspace(tf);
else
printf("Possible RT11 bootstrap block.\n");
}
}
int
gethdr(tf, hdrp)
int tf;
struct hdr *hdrp;
{
int n;
if (labelsize == sizeof(struct hdr))
n = read(tf, (char *)hdrp, sizeof(struct hdr));
else {
n = read(tf, buffer, labelsize);
bcopy((char *)hdrp, buffer, sizeof(struct hdr));
}
if (n == 0)
return(FALSE);
if (n != labelsize ||
strncmp(hdrp->h_labid, "HDR", LABID) != 0 ||
hdrp->h_labno != '1')
hdrerr(tf, hdrp);
return(TRUE);
}
hdrerr(tf, hdrp)
int tf;
struct hdr *hdrp;
{
int found, n;
printf("Warning: File label (HDR1) error - skipping\n");
found = FALSE;
while (!found) {
skipfile(tf);
if (labelsize == sizeof(struct hdr))
n = read(tf, (char *)hdrp, sizeof(struct hdr));
else {
n = read(tf, buffer, labelsize);
bcopy((char *)hdrp, buffer, sizeof(struct hdr));
}
if ((n == labelsize) &&
(strncmp(hdrp->h_labid, "HDR", LABID) == 0))
found = TRUE;
}
}
geteof(tf, eofp)
int tf;
struct hdr *eofp;
{
int n;
if (labelsize == sizeof(struct hdr))
n = read(tf, eofp, sizeof(struct hdr));
else {
n = read(tf, buffer, labelsize);
bcopy((char *)eofp, buffer, sizeof(struct hdr));
}
if (n != labelsize ||
strncmp(eofp->h_labid, "EOF", LABID) != 0 ||
eofp->h_labno != '1')
printf("Warning: File label (EOF1) error\n");
}
int
getrec(f, buf, size)
int f;
char *buf;
int size;
{
int n;
n = read(f, buf, size);
if (n < 0)
fatal("Read error (record may be larger than %db)\n",
size);
return(n);
}
getmark(tf, hdr2p, labseq)
int tf;
int labseq;
struct hd2 *hdr2p;
{
char rec[sizeof(struct hdr)];
char blkmax[BLKMAX+1], recmax[RECMAX+1];
char lstring[sizeof(struct hdr) + 1];
int n;
int s;
s = labseq;
s++;
n = read(tf, rec, sizeof(rec));
if (n == 0)
return;
if (n == sizeof(struct hdr) && (strncmp("HDR", rec, 3)==0)) {
bcopy((char *)hdr2p, rec, sizeof(struct hdr));
if (hdr2p->h2_labno == s) {
sncpy(blkmax, hdr2p->h2_blkmax, BLKMAX);
sncpy(recmax, hdr2p->h2_recmax, RECMAX);
if ((verbose) && (table))
prthdr2(&hdr2);
blocksize = max(blocksize, atoi(blkmax));
if (hdr2p->h2_datatype == 'D') {
linesize = 0;
Varlen = TRUE; }
else { linesize = max(linesize, atoi(recmax));
Varlen = FALSE; }
realloc(buffer,blocksize+10);
}
}
else if ((verbose) && (table)) {
sncpy(lstring, rec, sizeof(struct hdr));
printf("%s\n", lstring);
}
/* skip HDR3-9 */
while (n == sizeof(struct hdr) &&
(strncmp("HDR", rec, 3)==0 || strncmp("EOF", rec, 3)==0)) {
n = read(tf, rec, sizeof(rec));
if (n == 0)
return;
else if ((verbose) && (table)) {
sncpy(lstring, rec, sizeof(struct hdr));
printf("%s\n", lstring);
}
}
printf("Warning: tape mark missing\n");
}
cmphdreof(hdrp, eofp)
struct hdr *hdrp, *eofp;
{
char line[MAXLINE];
static int len = FILEID+SETID+SECNO+SEQNO+GENNO+GENVSNO+
CRDATE+EXDATE+1;
if (strncmp(hdrp->h_fileid, eofp->h_fileid, len) != 0 ||
strncmp(hdrp->h_system, eofp->h_system, SYSTEM) != 0) {
sncpy(line, hdrp->h_fileid, FILEID);
fprintf(stderr, "Warning: HDR and EOF labels for %s disagree\n",
line);
}
}
putvol(tf, volp)
int tf;
struct vol *volp;
{
int len;
if (labelsize == sizeof(struct vol)) {
write(tf, volp, sizeof(struct vol));
return;
}
bcopy(buffer, (char *)volp, sizeof(struct vol));
len = labelsize - sizeof(struct vol);
blcopy(&buffer[sizeof(struct vol)], "", len);
write(tf, buffer, labelsize);
}
puthdr(tf, hdrp)
int tf;
struct hdr *hdrp;
{
int len;
if (labelsize == sizeof(struct hdr)) {
write(tf, hdrp, sizeof(struct hdr));
return;
}
bcopy(buffer, (char *)hdrp, sizeof(struct hdr));
len = labelsize - sizeof(struct hdr);
blcopy(&buffer[sizeof(struct hdr)], "", len);
write(tf, buffer, labelsize);
}
prtvol(volp)
struct vol *volp;
{
char labid[LABID+1], serial[SERIAL+1], owner[OWNER+1];
sncpy(labid, volp->v_labid, LABID);
sncpy(serial, volp->v_serial, SERIAL);
sncpy(owner, volp->v_owner, OWNER);
printf("Volume label:\n");
printf("\tLabel: %s%c Serial: %s Access: %c\n",
labid, volp->v_labno, serial, volp->v_access);
printf("\tOwner: %s Standard: %c\n",
owner, volp->v_stdlabel);
}
prthdr(hdrp)
struct hdr *hdrp;
{
char labid[LABID+1], fileid[FILEID+1], setid[SETID+1];
char secno[SECNO+1], seqno[SEQNO+1];
char genno[GENNO+1], genvsno[GENVSNO+1];
char crdate[CRDATE+1], exdate[EXDATE+1];
char blocks[BLOCKS+1], system[SYSTEM+1];
sncpy(labid, hdrp->h_labid, LABID);
sncpy(fileid, hdrp->h_fileid, FILEID);
sncpy(setid, hdrp->h_setid, SETID);
sncpy(secno, hdrp->h_secno, SECNO);
sncpy(seqno, hdrp->h_seqno, SEQNO);
sncpy(genno, hdrp->h_genno, GENNO);
sncpy(genvsno, hdrp->h_genvsno, GENVSNO);
sncpy(crdate, hdrp->h_crdate, CRDATE);
sncpy(exdate, hdrp->h_exdate, EXDATE);
sncpy(blocks, hdrp->h_blocks, BLOCKS);
sncpy(system, hdrp->h_system, SYSTEM);
printf("File Label:\n");
printf("\tLabel: %s%c File: %s\n",
labid, hdrp->h_labno, fileid);
printf("\tSet: %s Section: %s Sequence: %s\n",
setid, secno, seqno);
printf("\tGeneration: %s Generation Version: %s\n",
genno, genvsno);
printf("\tCreated: %s Expires: %s Access: %c\n",
crdate, exdate, hdrp->h_access);
printf("\tBlocks: %s System: %s\n",
blocks, system);
}
prthdr2(hdrp)
struct hd2 *hdrp;
{
char labid[LABID+1];
char blkmax[BLKMAX+1], recmax[RECMAX+1];
char bytoffs[BYTOFFS+1];
sncpy(labid, hdrp->h2_labid, LABID);
sncpy(blkmax, hdrp->h2_blkmax, BLKMAX);
sncpy(recmax, hdrp->h2_recmax, RECMAX);
sncpy(bytoffs, hdrp->h2_bytoffs, BYTOFFS);
printf("File Label:\n");
printf("\tLabel: %s%c Datatype: %c\n",
labid, hdrp->h2_labno, hdrp->h2_datatype);
printf("\tMaximum block size: %s Maximum record size: %s\n",
blkmax, recmax);
printf("\tByte offset at head of block: %s\n",
bytoffs);
}
initvol(volp)
struct vol *volp;
{
struct passwd *passwp, *getpwuid();
blcopy(volp, "", sizeof(struct vol));
blcopy(volp->v_labid, "VOL", LABID);
volp->v_labno = '1';
blcopy(volp->v_serial, defvsn, SERIAL);
volp->v_access = ' ';
passwp = getpwuid(getuid());
blcopy(volp->v_owner, passwp->pw_name, OWNER);
if ((Varlen) || (Fixlen))
volp->v_stdlabel = '3';
else
volp->v_stdlabel = '1';
}
inithdr(hdrp, filename, seq)
struct hdr *hdrp;
char *filename;
int seq;
{
char seqno[SEQNO+1];
blcopy(hdrp, "", sizeof(struct hdr));
blcopy(hdrp->h_labid, "HDR", LABID);
hdrp->h_labno = '1';
blcopy(hdrp->h_fileid, filename, FILEID);
blcopy(hdrp->h_secno, "0001", SECNO);
utoaz(seq, seqno, SEQNO);
blcopy(hdrp->h_seqno, seqno, SEQNO);
blcopy(hdrp->h_genno, "0001", GENNO);
blcopy(hdrp->h_genvsno, "00", GENVSNO);
blcopy(hdrp->h_crdate, curdate, CRDATE);
blcopy(hdrp->h_exdate, alongtime, EXDATE);
blcopy(hdrp->h_blocks, "000000", BLOCKS);
blcopy(hdrp->h_system, "Unix V7", SYSTEM);
}
inithdr2(hdr2p, rectype, b, r)
struct hd2 *hdr2p;
int rectype;
int b, r;
{
char blkmax[BLKMAX+1];
char recmax[RECMAX+1];
blcopy(hdr2p, "", sizeof(struct hdr));
blcopy(hdr2p->h2_labid, "HDR", LABID);
hdr2p->h2_labno = '2';
hdr2p->h2_datatype = rectype;
utoaz(b, blkmax, BLKMAX);
blcopy(hdr2p->h2_blkmax, blkmax, BLKMAX);
utoaz(r, recmax, RECMAX);
blcopy(hdr2p->h2_recmax, recmax, RECMAX);
blcopy(hdr2p->h2_bytoffs, "00", BYTOFFS);
}
int
dblock(fp,buffer,blocksize)
FILE *fp;
char *buffer;
int blocksize;
{
FILE *fs;
char dbuffer[MAXLINE+5];
#if DEBUG
char tbuffer[ISOBLOCK + 1];
#endif
char *bb, *db;
int n, nl, nlm;
int brem;
int nf;
fs = fopen("#tmp.tmp", "w");
if (fs == NULL) fatal("can't create #tmp.tmp\n");
bb = buffer; brem = blocksize + 1; n = 1; nlm = 0;
while (n) {
n = drecord(fp, dbuffer);
nlm = max(nlm, n);
#if DEBUG
printf(" %s\n in dbuffer %d brem\n", dbuffer, brem);
#endif
if ((n) && ((brem -= n) > 0)) {
for(nl = 0; nl < n; ++nl) *bb++ = dbuffer[nl];
#if DEBUG
*bb = 0; printf("first try %s\n", buffer);
#endif
}
else {
brem += n;
#if DEBUG
printf(" %d fill bytes needed\n", brem);
#endif
while (brem-- > 0) *bb++ = '^';
bb = buffer; nl = n;
#if DEBUG
strncpy(tbuffer, buffer, blocksize);printf("%s\n", tbuffer);
#endif
nf = fwrite(buffer, blocksize, 1, fs);
if (n) {
for(nl = 0; nl < n; ++nl) *bb++ = dbuffer[nl];
#if DEBUG
strncpy(tbuffer, buffer, blocksize);printf("%s\n", tbuffer);
#endif
brem = blocksize - n;
}
}
}
fclose(fs);
return(nlm);
}
int
drecord(fp, lbuffer)
FILE *fp;
char *lbuffer;
{
char count[DBYTES+1];
int n;
n = filldln(fp, lbuffer);
utoaz(n, count, DBYTES);
bcopy(lbuffer, count, DBYTES);
return(n);
}
int
filldln(fp, lbuf)
FILE *fp;
char *lbuf;
{
int i, linelim;
register int c;
register char *lb;
lb = lbuf;
linelim = MAXLINE+DBYTES;
i = DBYTES;
lb += DBYTES;
while ((c = getc(fp)) && (c != EOF) && (c != '\n')) {
*lb++ = c;
if (i++ > linelim-1) break;
}
*lb = '\0';
if (c == '\n') return(i);
if (c == EOF) return(0);
printf("%d byte line too long; Broken into parts.\n", i);
return(i);
}
int
lblock(fp, buffer, lsize, bfactor)
FILE *fp;
char *buffer;
int lsize, bfactor;
{
register char *lp, *linelim;
register int c;
int i;
char *bp;
bp = buffer;
for (i=0; i<bfactor; i++) {
lp = bp;
linelim = &lp[lsize];
while (lp < linelim) {
c = getc(fp);
if (c == '\n' || c == EOF)
break;
*lp++ = c;
}
if (c == EOF && lp == bp)
break;
while (c != '\n' && c != EOF)
c = getc(fp);
while (lp < linelim)
*lp++ = ' ';
bp += lsize;
}
return(bp - buffer);
}
lunblock(fp, buffer, blen, lsize)
FILE *fp;
char *buffer;
int blen, lsize;
{
register char *lastp, *bp1;
char *bp, *buflim;
buflim = &buffer[blen];
bp = buffer;
while (bp < buflim) {
lastp = &bp[lsize-1];
while (lastp >= bp && isspace(*lastp))
lastp--;
for (bp1=bp; bp1<=lastp; bp1++)
putc(*bp1, fp);
putc('\n', fp);
bp += lsize;
}
}
blcopy(dest, src, n)
char *dest, *src;
int n;
{
int i;
i=0;
while (i < n && *src) {
*dest++ = *src++;
i++;
}
while (i++ < n)
*dest++ = ' ';
}
sncpy(dest, src, n)
char *dest, *src;
int n;
{
int i;
i = 0;
while (*src && i<n) {
*dest++ = *src++;
i++;
}
*dest = '\0';
}
utoaz(n, buf, size)
int n;
char *buf;
int size;
{
char *p;
p = &buf[size-1];
while (p >= buf && n != 0) {
*p = '0' + (n % 10);
n /= 10;
p--;
}
while (p >= buf) {
*p = '0';
p--;
}
}
tapemark(tf)
int tf;
{
struct mtop mtop;
mtop.mt_count = 1;
mtop.mt_op = MTWEOF;
ioctl(tf, MTIOCTOP, &mtop);
}
skipfile(tf)
int tf;
{
struct mtop mtop;
mtop.mt_count = 1;
mtop.mt_op = MTFSF;
ioctl(tf, MTIOCTOP, &mtop);
}
backspace(tf)
int tf;
{
struct mtop mtop;
mtop.mt_count = 1;
mtop.mt_op = MTBSR;
ioctl(tf, MTIOCTOP, &mtop);
}
/* getansidate -- return the current date in ansi format
*
* Ansi dates are strings of the form " yyddd" where
* yy = the year and ddd = the day in the year. There must
* be an initial blank.
*/
getansidate(curdate)
char *curdate;
{
time_t now, time();
struct tm *timep, *localtime();
now = time(NULL);
timep = localtime(&now);
curdate[0] = ' ';
utoaz(timep->tm_year, &curdate[1], 2);
utoaz(timep->tm_yday, &curdate[3], 3);
curdate[6] = '\0';
}
int
lookup(tab, name, Upper)
char *tab[];
char *name;
int Upper;
{
int i;
char lower[MAXLINE];
if (Upper) {
strcpy(lower, name);
makelower(lower);
}
for (i=0; tab[i] != NULL; i++)
#ifdef VARIAN
if (wildcmp(tab[i], name, WILDCARD) == 0 ||
(Upper && wildcmp(tab[i], lower, WILDCARD)==0))
#else
if (strcmp(tab[i], name) == 0 ||
(Upper && strcmp(tab[i], lower)==0))
#endif VARIAN
return(TRUE);
return(FALSE);
}
makelower(s)
char *s;
{
register char *p;
p = s;
while (*p) {
if (isupper(*p))
*p = tolower(*p);
p++;
}
}
makeupper(s)
char *s;
{
register char *p;
p = s;
while (*p) {
if (islower(*p))
*p = toupper(*p);
p++;
}
}
int
haslower(p)
register char *p;
{
while (*p) {
if (islower(*p))
return(TRUE);
p++;
}
return(FALSE);
}
toRT11(name)
char *name;
{
char buf[32], *extp;
extp = index(name, '.');
if (extp != NULL) {
*extp = '\0';
extp++;
}
blcopy(buf, name, 6);
buf[6] = '.';
if (extp != NULL)
blcopy(&buf[7], extp, 3);
else
strcpy(&buf[7], "ext");
buf[10] = '\0';
strcpy(name, buf);
}
fromRT11(name)
char *name;
{
char *op, *np;
op = np = name;
while (*op) {
if (!isspace(*op))
*np++ = *op;
op++;
}
*np = '\0';
}
trimsp(s)
char *s;
{
register char *p;
p = &s[strlen(s)-1];
while (p >= s && isspace(*p))
p--;
*++p = '\0';
}
bcopy(dest, src, size)
char *dest, *src;
int size;
{
while (size-- > 0)
*dest++ = *src++;
}
int
max(a, b)
int a, b;
{
if (a > b)
return(a);
return(b);
}
int
checkw(c, name)
char c, *name;
{
if (!confirm)
return(TRUE);
printf("%c %s:", c, name);
c = getchar();
if (c != '\n')
while ((c = getchar()) != '\n')
;
return(c == 'y' || c == 'Y');
}
/* VARARGS */
fatal(s, a1, a2, a3, a4)
char *s;
{
fprintf(stderr, "ansitar: ");
fprintf(stderr, s, a1, a2, a3, a4);
exit(1);
}
#ifdef VARIAN
/* varunblock - unblock variable length records ("D" format)
* Beginning of each record contains a 4 digit number which is the
* length of the record (including the count).
* There are no line terminators (CR or LF).
*/
varunblock(fp, buffer, blen)
FILE *fp;
char *buffer;
int blen;
{ /* the function now returns the # of bytes it decided to write */
register char *lastp, *bp1;
char *bp, *buflim;
int count;
int newblen; /* this will count the actual bytes written out */
buflim = &buffer[blen];
bp = buffer;
newblen = 0;
#if DEBUG
DBG" varunblock called. length %d\n",blen);
if(DEBUG)hexdmp(" buffer passed to varunblock",buffer,blen);
DBG" ");
#endif DEBUG
while (bp < buflim) {
#if DEBUG
DBG" count being made from %2x %2x %2x %2x %2x\n",
*bp,*(bp+1),*(bp+2),*(bp+3),*(bp+4));
#endif
sscanf(bp,"%4d",&count);
count = count - 4; /* count includes the count itself */
#if DEBUG
DBG" count %3d\n ",count);
#endif
if (*bp == 0x5e) /* if fill encountered for length */
{ /* then abandon this record */
#if DEBUG
DBG" hit filler. assume eor. break\n");
#endif
break;
}
bp = bp+4; /* point to the end of line */
lastp = bp + count;
while (bp<lastp)
{
#if DEBUG
if(DEBUG) putc(*bp, stderr);
#endif
putc(*bp++, fp);
newblen++;
}
#if DEBUG
if(DEBUG) putc('\n', stderr);
#endif
putc('\n', fp);
newblen++;
}
return(newblen);
}
wildcmp(wilds,str,wc) /* compare 2 strings. 1st can have a wildcard '*' */
char *wilds; /* input string possibly containing a wildcard chr*/
char *str; /* 2nd input string. wild chrs in it aren't 'wild'*/
char wc; /* the 'wild card' character, often a '*' */
{ /* function return is 0 if equal (like strcmp). < > not supported */
char *l,*s;
int flag; /* will watch for multiple *'s in 'wild'*/
char wcrd;
if (strlen(str) == 0) return(-1); /* don't match phantom */
wcrd = wc & 127;
flag = 0; /* wildcard not encountered yet */
for (l=wilds,s=str ; *l != '\0' ; )
{
if (*l == wcrd) /* if wildcard emcountered, adjust pointers*/
{
if (flag) return(0);
flag = 1;
l++; /* skip the wildcard */
s = str + strlen(str) - (strlen(wilds) - (l - wilds) );
}
else{ /* no wildcard, increment pointers normally */
if (*l != *s) return(*l - *s);
l++;
s++;
}
}
if (*s != '\0') return(*l - *s);
return(0); /* returning "success" indicator. they were equal */
}
#endif VARIAN
#ifdef PIP
/*****************************************************************
* TAG( pipunblock )
*
* Unblock pip records. These are in a counted format with a 4 byte
* count, followed by the record. (Count includes the length of the
* count). Blank space at the end of a block is filled with '^'
* characters.
*/
pipunblock(fp, buffer, n)
FILE *fp;
char *buffer;
{
register char *cp;
int len, i;
for (cp=buffer; cp<buffer+n; )
{
for (i=0, len=0; i<4; i++)
len = len*10 + *cp++ - '0';
for (len -= 4; len > 0; len--)
putc(*cp++, fp);
putc('\n', fp);
while (*cp == '^' && cp<buffer+n)
cp++;
}
}
/*****************************************************************
* TAG( pipblock )
*
* Read lines from the input file and block them pip-style into the
* buffer. Make logical blocks of 512 bytes and fill space at the end
* of the logical blocks with '^' characters.
*/
pipblock(fp, buffer, blocksize)
FILE *fp;
char *buffer;
{
register char *cp;
static char linebuf[512]; /* lines not allowed longer than this? */
static int nline = 0;
int n;
if (blocksize%512)
{
fprintf(stderr, "Blocksize must be a multiple of 512 for pip tapes\n");
exit(1);
}
for (cp=buffer; cp<(buffer+blocksize); )
{
if (nline <= 0)
if (fgets(linebuf, 508, fp) == NULL)
nline = -1;
else
{
linebuf[508] = '\0';
nline = strlen(linebuf);
if (linebuf[nline-1] == '\n')
linebuf[--nline] = '\0';
}
if (nline > (508 - (cp-buffer)%512) ||
(nline < 0 && (cp-buffer)%512 != 0))
while ( (cp-buffer)%512 != 0 )
*cp++ = '^';
if (cp-buffer >= blocksize || nline < 0)
return cp-buffer;
sprintf(cp, "%04d", nline+4);
cp += 4;
strncpy(cp, linebuf, 508);
cp += nline;
nline = 0;
}
return cp-buffer; /* should never get here, but you never know */
}
#endif PIP
'StopHere'
More information about the Comp.sources.unix
mailing list