[comp.sources.unix] v10i089: Magtape handling package, Part02/02

rs@uunet.UU.NET (Rich Salz) (08/04/87)

Submitted-by: Dick Grune <dick@cs.vu.nl>
Posting-number: Volume 10, Issue 89
Archive-name: magtapetools/Part02

: --------------------------- cut here --------------------------
PATH=/bin:/usr/bin
echo Extracting \a\n\s\i\.\h
sed 's/^X//' > \a\n\s\i\.\h << '+ END-OF-FILE '\a\n\s\i\.\h
X/*	This file is part of the magtape handling package MAG.
X	Written by Dick Grune, Vrije Universiteit, Amsterdam.
X*/
X
X#include	<stdio.h>
X
Xextern char *strcpy();
X
X#define	NL	'\n'
X#define	TAB	'\t'
X#define	SP	' '
X#define	EOS	'\0'
X
X#define	TRUE	1
X#define	FALSE	0
X
X#define	MAXSTR	128
X
X/*
X * It is tempting to use structs for the declaration of the label data
X * structures, access the fields through selectors and let the C-compiler
X * do the offset calculation. There are, however, two problems:
X *    1. alignment is different on different machines (VAX vs. PDP11),
X *    2. according to the book the fields may even be arranged in inverse
X *       order.
X * So structs are out and defines are in.
X * A field is implemented as a pair: an address and a length.
X */
X
X/* the general fields */
X#define	Whole(p)	&(p)[0], sizeof (p)
X#define	Labidf(p)	&(p)[0], 4
X
X/* the VOL1 label */
X#define	Volidf(p)	&(p)[4], 6
X#define	Volacc(p)	&(p)[10], 1
X#define	Sp1(p)		&(p)[11], 26
X#define	Ownidf(p)	&(p)[37], 14
X#define	Sp2(p)		&(p)[51], 28
X#define	Labvers(p)	&(p)[79], 1
X
X/* dates */
X#define	Sp(p)		&(p)[0], 1
X#define	Date(p)		&(p)[1], 5
X#define	Yr(p)		&(p)[1], 2
X#define	Yd(p)		&(p)[3], 3
X
X/* the HDR1 label */
X#define	Fileidf(p)	&(p)[4], 17
X#define	Filesetidf(p)	&(p)[21], 6
X#define	Filsecnum(p)	&(p)[27], 4
X#define	Filseqnum(p)	&(p)[31], 4
X#define	Gennum(p)	&(p)[35], 4
X#define	Genversnum(p)	&(p)[39], 2
X#define	Creatdate(p)	&(p)[41], 6
X#define	Expirdate(p)	&(p)[47], 6
X#define	Fileacc(p)	&(p)[53], 1
X#define	Blkcount(p)	&(p)[54], 6
X#define	Syscode(p)	&(p)[60], 13
X#define	Sp3(p)		&(p)[73], 7
X
X/* the HDR2 label */
X#define	Recformat(p)	&(p)[4], 1
X#define	Blklength(p)	&(p)[5], 5
X#define	Reclength(p)	&(p)[10], 5
X#define	Syssoftw(p)	&(p)[15], 35
X#define	Bufoffset(p)	&(p)[50], 2
X#define	Sp4(p)		&(p)[52], 28
X
X/* the USRn label */
X#define	Contents(p)	&(p)[4], 76
X
X
Xextern int unit;
Xextern char *nmdns;
Xextern TPFILE *tf;
X
X#define	ASK_NO	0	/* use default and check */
X#define	ASK_YES	1	/* ask and check */
X#define	ASK_SUG	2	/* suggest default and check */
X#define	ASK_ERR	3	/* ask again and check */
X
X/*	Macros to define an additional control structure to handle
X	interactive input, under the presence of user errors.
X*/
X#define	inmood(md)	{int mood = md; for (;;mood=ASK_ERR)
X#define	iferr(cond)	if(cond){print_loc();
X#define	enderr		continue;}
X#define	endmood		break;}
X
Xextern char *sps2txt(), *str2txt(), *expl2str(), *tty_line(), *tty_str();
Xextern char *enq_str(), *fld2str(), *char2str();
Xextern int enq_int(), isascstr(), fld2int();
Xextern fld2fld(), str2fld(), prf_s(), errors();
X
Xstruct format	{
X	char type;
X	int (*checkpar)();
X	int (*cpblk)();
X};
X
Xextern struct format formats[];
Xextern struct format *format_of_type();
X
Xextern char filename[MAXSTR];
Xextern FILE *file;
Xextern int filseqnum;
Xextern int filsecnum;
Xextern char rectype[1];
Xextern struct format *recformat;
Xextern int blklength;
Xextern int reclength;
Xextern int bufoffset;
Xextern int reccount;
Xextern int blkcount;
X
Xextern char VOL1buf[80];
Xextern char HDR1buf[80];
Xextern char HDR2buf[80];
+ END-OF-FILE ansi.h
chmod 'u=rw,g=r,o=r' \a\n\s\i\.\h
set `sum \a\n\s\i\.\h`
sum=$1
case $sum in
43328)	:;;
*)	echo 'Bad sum in '\a\n\s\i\.\h >&2
esac
echo Extracting \e\t\o\a\.\h
sed 's/^X//' > \e\t\o\a\.\h << '+ END-OF-FILE '\e\t\o\a\.\h
X/*	This file is part of the magtape handling package MAG.
X	Written by Dick Grune, Vrije Universiteit, Amsterdam.
X*/
X
Xextern char _etoa[];			/* from etoa.c */
X
X#define	ebc2asc(c)	(_etoa[(c)&0377])
+ END-OF-FILE etoa.h
chmod 'u=rw,g=r,o=r' \e\t\o\a\.\h
set `sum \e\t\o\a\.\h`
sum=$1
case $sum in
11080)	:;;
*)	echo 'Bad sum in '\e\t\o\a\.\h >&2
esac
echo Extracting \o\p\t\i\o\n\s\.\h
sed 's/^X//' > \o\p\t\i\o\n\s\.\h << '+ END-OF-FILE '\o\p\t\i\o\n\s\.\h
X/*	This file is part of the magtape handling package MAG.
X	Written by Dick Grune, Vrije Universiteit, Amsterdam.
X*/
X
X/*	Having a chunk out of a switch statement as a separate include
X	file is unusual, but this file does implement a conceptual unit:
X	the handling of the standard command line options for describing
X	a generalized magtape.  See mag.1.
X	
X	This include file assumes
X		aux.h		to be included
X		tp.h		idem
X	uses and updates
X		argc		as supplied by main()
X		argv		idem
X	sets
X		unit		the unit number
X		nmdns		file name or density
X	and jumps to
X		Lbad		on bad command line parameters
X*/
X
X	default:
X		goto Lbad;
X	case 'c':			/* character device */
X		unit = TP_CDEV;
X		if (argc < 2)
X			goto Lbad;
X		nmdns = argv[1];
X		argc--, argv++;
X		break;
X	case 'f':			/* tape image */
X		unit = TP_IMAG;
X		if (argc < 2)
X			goto Lbad;
X		nmdns = argv[1];
X		argc--, argv++;
X		break;
X	case 'h':			/* high density */
X		nmdns = TP_DENH;
X		break;
X	case 'l':			/* low density */
X		nmdns = TP_DENL;
X		break;
X	case 'm':			/* unit number (real tape unit) */
X		if (argc < 2)
X			goto Lbad;
X		if (!is_digit(argv[1][0]))
X			goto Lbad;
X		unit = atoi(argv[1]);
X		argc--, argv++;
X		break;
+ END-OF-FILE options.h
chmod 'u=rw,g=r,o=r' \o\p\t\i\o\n\s\.\h
set `sum \o\p\t\i\o\n\s\.\h`
sum=$1
case $sum in
18446)	:;;
*)	echo 'Bad sum in '\o\p\t\i\o\n\s\.\h >&2
esac
echo Extracting \a\n\s\i\.\c
sed 's/^X//' > \a\n\s\i\.\c << '+ END-OF-FILE '\a\n\s\i\.\c
X/*	This file is part of the magtape handling package MAG.
X	Written by Dick Grune, Vrije Universiteit, Amsterdam.
X*/
X
X#include	"aux.h"
X#include	"tp.h"
X#include	"ansi.h"
X
Xextern char *sprintf();
X
Xint unit = 0;
Xchar *nmdns = TP_DENN;
XTPFILE *tf = NULL;
X
Xchar filename[MAXSTR];
XFILE *file = NULL;
Xint filseqnum = 0;
Xint filsecnum = 1;
Xchar rectype[1] = 'F';
Xstruct format *recformat;
Xint blklength = 1920;
Xint reclength = 80;
Xint bufoffset = 0;
Xint reccount;
Xint blkcount;
X
Xchar VOL1buf[80];
Xchar HDR1buf[80];
Xchar HDR2buf[80];
X
Xchar *
Xsps2txt(p)	{
X	return p == 0 ? "<empty>" : p == 1 ? "<space>" : "<spaces>";
X}
X
Xchar *
Xstr2txt(s)
X	char *s;
X{
X	int p = 0;
X
X	while (s[p] != EOS)	{
X		if (s[p] != SP)
X			return s;
X		p++;
X	}
X	return sps2txt(p);
X}
X
X/* An expl(anation) is an explanatory string which contains the name of the
X * object being explained as the first item between ` and ' . The expl may
X * contain one %s which is replaced by the default (string) value.
X */
X
Xchar * /* transient */
Xexpl2str(expl)
X	char *expl;
X{
X	static char str[MAXSTR];
X	char *nm = expl, cnt = 0;
X	
X	while (*nm != EOS && *nm != '`')	{
X		nm++;
X	}
X	nm++;
X	while (*nm != EOS && *nm != '\'')	{
X		if (cnt < MAXSTR-1)
X			str[cnt++] = *nm;
X		nm++;
X	}
X	str[cnt] = EOS;
X	return str;
X}
X
Xchar * /* transient */
Xtty_line()	{
X	static char ans[MAXSTR];
X	int cnt = 0;
X	int ch;
X
X	while ((ch = getchar()) != NL)	{
X		if (ch == EOF)
X			errors("\n*** No interaction!!!");
X		if (cnt < MAXSTR-1)
X			ans[cnt++] = ch;
X	}
X	ans[cnt] = EOS;
X	return ans;
X}
X
Xchar * /* transient */
Xtty_str(prompt, expl, md, def)
X	char *prompt, *expl, md, *def;
X{
X	static char conversation = FALSE;
X	char *str;
X	int err = 0;
X
X	if (!conversation)	{
X		prf_s("\n\
X	I shall have to ask some questions; to get more information,\n\
X	answer a question with a single question mark (?).\n\n", "");
X		conversation = TRUE;
X	}
X	while (err < 3)	{
X		printf(prompt, expl2str(expl));
X		str= tty_line();
X		if (strcmp(str, "?") == 0)	{
X			printf("\n");
X			prf_s(expl, def);
X			printf("\n");
X		}
X		else
X		if (strlen(str) > 0)
X			return str;
X		else
X		if (md == ASK_SUG)
X			return NULL;
X		else	{
X			printf("I do need an answer!\n");
X			err++;
X		}
X	}
X	errors("\nSorry");
X	return str;
X}
X
Xchar * /* transient */
Xenq_str(expl, md, def)
X	char *expl, *def;
X{
X	char *str;
X
X	switch (md)	{
X	case ASK_NO:
X		str = def;
X		break;
X	case ASK_YES:
X		print_loc();
X		str = tty_str("Please type your %s: ", expl, md, def);
X		break;
X	case ASK_SUG:
X		print_loc();
X		printf("Default %s: ", expl2str(expl));
X		prf_s("%s\n", str2txt(def));
X		str = tty_str("Please type a new %s, or press RETURN: ",
X			expl, md, def);
X		if (str == NULL)
X			str = def;
X		break;
X	case ASK_ERR:
X		str = tty_str("Please type a new %s: ", expl, md, def);
X		break;
X	}
X
X	return str;
X}
X
Xint
Xenq_int(expl, md, def, max)
X	char *expl;
X{
X	int res;
X	char deftxt[MAXSTR];
X
X	VOID(sprintf(deftxt, "%d", def));
X	inmood (md)	{
X		char *str = enq_str(expl, mood, deftxt);
X		char *ptr = str;
X		char ch;
X
X		res = 0;
X		while ((ch = *ptr++) != EOS)	{
X			int dig = char2int(ch) -'0';
X
X			if (dig < 0 || dig > 9)	{
X				res = -1;
X				break;
X			}
X			if (res > max/10 || res*10 > max - dig)	{
X			/* airtight, waterproof and overflow-resistant */
X				res = -2;
X				break;
X			}
X			res = res*10 + dig;
X		}
X		iferr (res == -1)	{
X			printf("The %s `%s' is not numeric\n",
X					expl2str(expl), str);
X			enderr;
X		}
X		iferr (res == -2)	{
X			printf("The %s `%s' is too large\n",
X					expl2str(expl), str);
X			printf("The maximum value is %d\n", max);
X			enderr;
X		}
X		endmood;
X	}
X	return res;
X}
X
Xint
Xisascstr(str)
X	char *str;
X{
X	char ch;
X
X	while ((ch = *str++) != EOS)
X		if (!is_ascii95(ch))
X			return FALSE;
X	return TRUE;
X}
X
Xint
Xfld2int(addr, size)
X	char *addr;
X{
X	int res = 0, i;
X
X	for (i = 0; i < size; i++)	{
X		char ch = addr[i];
X		int dig = char2int(ch) - '0';
X		
X		if (ch == SP)
X			continue;
X		if (dig < 0 || dig > 9)
X			return -1;
X		res = res * 10 + dig;
X	}
X	return res;
X}
X
Xchar * /* transient */
Xfld2str(addr, size)
X	char *addr;
X{
X	static char str[MAXSTR];
X	int i;
X
X	for (i = 0; i < size; i++)
X		if (i < MAXSTR-1)
X			str[i] = addr[i];
X	while (i > 0 && str[i-1] == SP)
X		i--;
X	str[i] = EOS;
X	return str;
X}
X
Xfld2fld(str, s1, addr, s2)
X	char *str, *addr;
X{
X	if (s1 != s2)
X		abort();
X	while (s1-- > 0)
X		*addr++ = *str++;
X}
X
Xstr2fld(str, addr, size)
X	char *str, *addr;
X{
X	while (size-- > 0)
X		*addr++ = *str != EOS ? *str++ : SP;
X}
X
Xchar * /* transient */
Xchar2str(ch)	{
X	static char buff[7];
X
X	if (is_ascii95(ch))
X		VOID(sprintf(buff, "%c", ch));
X	else
X		VOID(sprintf(buff, "\\[%03o]", char2int(ch)));
X	return buff;
X}
X
X/*
X * `prf_s' prints a possibly ugly string `s' under a format `f' that may
X * be so long that it normally blows up the `printf' routine.
X */
Xprf_s(f, s)
X	char *f, *s;
X{
X	char fch;
X
X	while ((fch = *f++) != EOS)	{
X		if (fch != '%')
X			putchar(fch);
X		else	{
X			int sch;
X
X			f++;
X			while ((sch = *s++) != EOS)
X				printf("%s", char2str(sch));
X		}
X	}
X}
X
Xerrors(str)
X	char *str;
X{
X	printf("%s\n", str);
X	if (tf != NULL)
X		tpclose(tf);
X	exit(1);
X}
X
Xstruct format *
Xformat_of_type(ch)
X	char ch;
X{
X	struct format *fm;
X
X	for (fm = &formats[0]; fm->type != EOS; fm++)
X		if (fm->type == ch)
X			return fm;
X	return NULL;
X}
+ END-OF-FILE ansi.c
chmod 'u=rw,g=r,o=r' \a\n\s\i\.\c
set `sum \a\n\s\i\.\c`
sum=$1
case $sum in
48369)	:;;
*)	echo 'Bad sum in '\a\n\s\i\.\c >&2
esac
echo Extracting \e\t\o\a\.\c
sed 's/^X//' > \e\t\o\a\.\c << '+ END-OF-FILE '\e\t\o\a\.\c
X/*	This file is part of the magtape handling package MAG.
X	Written by Dick Grune, Vrije Universiteit, Amsterdam.
X*/
X
X/*	To convert from EBCDIC to Ascii you need the table
X	USASCII-8 TO EBCDIC-8 CORRESPONDENCE rather than the reverse,
X	which strikes me as kind of counterintuitive.
X	
X	This table is Table 4 from
X	Communications of the ACM, Vol 11, #11, Nov 1968, p 787.
X*/
X
X#define	S(c,r)	(c<<4) + r	/* implements the C/R convention */
X
Xchar _etoa[] =	{		/* to be used in ebc2asc() */
X	/* col 0 */
X	S( 0, 0), S( 0, 1), S( 0, 2), S( 0, 3),
X	S( 9,12), S( 0, 9), S( 8, 6), S( 7,15),
X	S( 9, 7), S( 8,13), S( 8,14), S( 0,11),
X	S( 0,12), S( 0,13), S( 0,14), S( 0,15),
X	/* col 1 */
X	S( 1, 0), S( 1, 1), S( 1, 2), S( 1, 3),
X	S( 9,13), S( 8, 5), S( 0, 8), S( 8, 7),
X	S( 1, 8), S( 1, 9), S( 9, 2), S( 8,15),
X	S( 1,12), S( 1,13), S( 1,14), S( 1,15),
X	/* col 2 */
X	S( 8, 0), S( 8, 1), S( 8, 2), S( 8, 3),
X	S( 8, 4), S( 0,10), S( 1, 7), S( 1,11),
X	S( 8, 8), S( 8, 9), S( 8,10), S( 8,11),
X	S( 8,12), S( 0, 5), S( 0, 6), S( 0, 7),
X	/* col 3 */
X	S( 9, 0), S( 9, 1), S( 1, 6), S( 9, 3),
X	S( 9, 4), S( 9, 5), S( 9, 6), S( 0, 4),
X	S( 9, 8), S( 9, 9), S( 9,10), S( 9,11),
X	S( 1, 4), S( 1, 5), S( 9,14), S( 1,10),
X	/* col 4 */
X	S( 2, 0), S(10, 0), S(10, 1), S(10, 2),
X	S(10, 3), S(10, 4), S(10, 5), S(10, 6),
X	S(10, 7), S(10, 8), S( 5,11), S( 2,14),
X	S( 3,12), S( 2, 8), S( 2,11), S( 2, 1),
X	/* col 5 */
X	S( 2, 6), S(10, 9), S(10,10), S(10,11),
X	S(10,12), S(10,13), S(10,14), S(10,15),
X	S(11, 0), S(11, 1), S( 5,13), S( 2, 4),
X	S( 2,10), S( 2, 9), S( 3,11), S( 5,14),
X	/* col 6 */
X	S( 2,13), S( 2,15), S(11, 2), S(11, 3),
X	S(11, 4), S(11, 5), S(11, 6), S(11, 7),
X	S(11, 8), S(11, 9), S( 7,12), S( 2,12),
X	S( 2, 5), S( 5,15), S( 3,14), S( 3,15),
X	/* col 7 */
X	S(11,10), S(11,11), S(11,12), S(11,13),
X	S(11,14), S(11,15), S(12, 0), S(12, 1),
X	S(12, 2), S( 6, 0), S( 3,10), S( 2, 3),
X	S( 4, 0), S( 2, 7), S( 3,13), S( 2, 2),
X
X	/* col 8 */
X	S(12, 3), S( 6, 1), S( 6, 2), S( 6, 3),
X	S( 6, 4), S( 6, 5), S( 6, 6), S( 6, 7),
X	S( 6, 8), S( 6, 9), S(12, 4), S(12, 5),
X	S(12, 6), S(12, 7), S(12, 8), S(12, 9),
X	/* col 9 */
X	S(12,10), S( 6,10), S( 6,11), S( 6,12),
X	S( 6,13), S( 6,14), S( 6,15), S( 7, 0),
X	S( 7, 1), S( 7, 2), S(12,11), S(12,12),
X	S(12,13), S(12,14), S(12,15), S(13, 0),
X	/* col A */
X	S(13, 1), S( 7,14), S( 7, 3), S( 7, 4),
X	S( 7, 5), S( 7, 6), S( 7, 7), S( 7, 8),
X	S( 7, 9), S( 7,10), S(13, 2), S(13, 3),
X	S(13, 4), S(13, 5), S(13, 6), S(13, 7),
X	/* col B */
X	S(13, 8), S(13, 9), S(13,10), S(13,11),
X	S(13,12), S(13,13), S(13,14), S(13,15),
X	S(14, 0), S(14, 1), S(14, 2), S(14, 3),
X	S(14, 4), S(14, 5), S(14, 6), S(14, 7),
X	/* col C */
X	S( 7,11), S( 4, 1), S( 4, 2), S( 4, 3),
X	S( 4, 4), S( 4, 5), S( 4, 6), S( 4, 7),
X	S( 4, 8), S( 4, 9), S(14, 8), S(14, 9),
X	S(14,10), S(14,11), S(14,12), S(14,13),
X	/* col D */
X	S( 7,13), S( 4,10), S( 4,11), S( 4,12),
X	S( 4,13), S( 4,14), S( 4,15), S( 5, 0),
X	S( 5, 1), S( 5, 2), S(14,14), S(14,15),
X	S(15, 0), S(15, 1), S(15, 2), S(15, 3),
X	/* col E */
X	S( 5,12), S( 9,15), S( 5, 3), S( 5, 4),
X	S( 5, 5), S( 5, 6), S( 5, 7), S( 5, 8),
X	S( 5, 9), S( 5,10), S(15, 4), S(15, 5),
X	S(15, 6), S(15, 7), S(15, 8), S(15, 9),
X	/* col F */
X	S( 3, 0), S( 3, 1), S( 3, 2), S( 3, 3),
X	S( 3, 4), S( 3, 5), S( 3, 6), S( 3, 7),
X	S( 3, 8), S( 3, 9), S(15,10), S(15,11),
X	S(15,12), S(15,13), S(15,14), S(15,15)
X};
X
+ END-OF-FILE etoa.c
chmod 'u=rw,g=r,o=r' \e\t\o\a\.\c
set `sum \e\t\o\a\.\c`
sum=$1
case $sum in
05699)	:;;
*)	echo 'Bad sum in '\e\t\o\a\.\c >&2
esac
echo Extracting \a\n\s\i\r\.\c
sed 's/^X//' > \a\n\s\i\r\.\c << '+ END-OF-FILE '\a\n\s\i\r\.\c
X/*	This file is part of the magtape handling package MAG.
X	Written by Dick Grune, Vrije Universiteit, Amsterdam.
X*/
X
X/*
X * Name: ansir, read ANSI standard labelled tape
X * Version: 820314
X */
X
X#define	MSGUSE	"Usage: ansir [-cfhlmijnpg] [ name ... ]"
X
Xextern char *strncpy();
X
X#include	"aux.h"
X#include	"tp.h"
X#include	"ansi.h"
X#include	"etoa.h"
X
X#define	MAXBLK	TP_MAXB
X#define	MINSIZE	6			/* smaller is a noise block */
X#define	CRECSEP	"\n"			/* record separator for coded files */
X
Xchar iflag = FALSE, jflag = FALSE, nflag = FALSE, pflag = FALSE, gflag = FALSE;
Xchar ok_fln, ok_rct, ok_blk, ok_rec, ok_bfo, ok_loc, skip_it;
Xchar **filelist = NULL;
X
Xchar *labcode = NULL;
Xchar *filecode = NULL;	/* may be `ascii', `ebcdic' or `binary' */
Xchar *ascii = "ASCII";
Xchar *ebcdic = "EBCDIC";
Xchar *binary = "BINARY";
Xchar binrecsep[MAXSTR];
X
Xint bsize = 0;
Xchar block[MAXBLK];
X
X#define	MAXUGLY	99	/* upper limit for tallying */
Xchar uglies[256];	/* for tallying non-UNIX-ASCII chars */
Xlong tot_uglies;
X
Xint HDR1blc;	/* block count as found in HDR1-label */
X
Xmain(argc, argv)
X	int argc;
X	char *argv[];
X{
X	argc--, argv++;
X	while (argc > 0 && argv[0][0] == '-')	{
X		char *pp = argv[0];
X		
X		while (*++pp)	{
X			switch (*pp)	{
X			/* insert cases to handle the standard options */
X#include	"options.h"
X			/* special options */
X			case 'g':
X				gflag = TRUE;
X				break;
X			case 'i':
X				iflag = TRUE;
X				break;
X			case 'j':
X				iflag = jflag = TRUE;
X				break;
X			case 'n':
X				nflag = TRUE;
X				break;
X			case 'p':
X				pflag = TRUE;
X				break;
X			}
X		}
X		argc--, argv++;
X	}
X
X	if (argc > 0)
X		filelist = argv;
X
X	tf = tpopen(unit, nmdns, "rx");
X	nextblk();
X
X	lblVOL1();
X	lblUSR("UVL");
X	while (bsize > 0)	{
X		clearflags();
X		lblHDR1();
X		lblHDR2();
X		lblUSR("HDR");
X		lblUSR("UHL");
X		read_tm();
X		copy();
X		lblEOF1();
X		lblEOF2();
X		lblUSR("EOF");
X		lblUSR("UTL");
X		read_tm();
X	}
X	if (pflag)
X		printf("\nEnd of tape\n");
X	tpclose(tf);
X	exit(0);
X
XLbad:
X	errors(MSGUSE);
X	exit(1);
X}
X
Xclearflags()	{
X	ok_fln = ok_rct = ok_blk = ok_rec = ok_bfo = ok_loc = skip_it = FALSE;
X}
X
X/*
X * Reads the VOL1-label and prints its contents
X */
X
XlblVOL1()	{
X
X	if (!label("VOL1", Whole(VOL1buf)))	{
X		missing("VOL1");
X		return;
X	}
X
X	if (pflag)
X		prVOL1();
X}
X
XlblUSR(idf)
X	char *idf;
X{
X	char USRnbuf[80];
X
X	while (label(idf, Whole(USRnbuf)))
X		if (pflag && !skip_it)	{
X			prhead(Labidf(USRnbuf));
X			prfield("Contents", Contents(USRnbuf));
X		}
X}
X
X/*
X * Reads the HDR1-label, prints its contents, and sets `filename'
X */
X
XlblHDR1()	{
X
X	filseqnum++;
X	if (!label("HDR1", Whole(HDR1buf)))	{
X		missing("HDR1");
X		ok_fln = FALSE;
X		return;
X	}
X
X	strcpy(filename, fld2str(Fileidf(HDR1buf)));
X	ok_fln = TRUE;
X
X	if (!interesting(filename))	{
X		skip_it = TRUE;
X		return;
X	}
X
X	if (pflag)
X		prHDR1();
X
X	if (fld2int(Filsecnum(HDR1buf)) != filsecnum)	{
X		print_loc();
X		printf("File section number not %d\n", filsecnum);
X	}
X	if (fld2int(Filseqnum(HDR1buf)) != filseqnum)	{
X		print_loc();
X		printf("File sequence number not in order\n");
X	}
X
X	HDR1blc = fld2int(Blkcount(HDR1buf));
X	if (chk_int("block count", HDR1blc) && HDR1blc != 0)	{
X		print_loc();
X		printf("Block count starts from %d\n", HDR1blc);
X	}
X}
X
X/*
X * Reads the HDR2-label, prints its contents and sets
X * `recformat', `blklength', `reclength' and `bufoffset'.
X */
X
XlblHDR2()	{
X	int found = label("HDR2", Whole(HDR2buf));
X
X	if (skip_it)
X		return;
X
X	if (!found)	{
X		missing("HDR2");
X		ok_rct = ok_blk = ok_rec = ok_bfo = FALSE;
X		return;
X	}
X
X	if (pflag)
X		prHDR2();
X
X	fld2fld(Recformat(HDR2buf), Whole(rectype));
X	ok_rct = TRUE;
X	blklength = fld2int(Blklength(HDR2buf));
X	ok_blk = chk_int("block length", blklength);
X	reclength = fld2int(Reclength(HDR2buf));
X	ok_rec = chk_int("record length", reclength);
X	bufoffset = fld2int(Bufoffset(HDR2buf));
X	ok_bfo = chk_int("buffer offset", bufoffset);
X}
X
Xint
Xlabel(idf, addr, size)
X	char *idf, *addr;
X{
X	if (bsize <= 0)
X		return FALSE;
X	if (labcode != NULL)
X		return is_lab(idf, addr, size);
X	labcode = ascii;
X	if (is_lab(idf, addr, size))
X		return TRUE;
X	labcode = ebcdic;
X	if (is_lab(idf, addr, size))
X		return TRUE;
X	labcode = NULL;
X	return FALSE;
X}
X
Xint
Xis_lab(idf, addr, size)
X	char *idf, *addr;
X{
X	int sz = bsize < size ? bsize : size;
X
X	VOID(strncpy(addr, block, sz));
X	if (labcode == ebcdic)
X		conv(addr, sz);
X	str2fld("", addr+sz, size-sz);
X	if (strhead(idf, addr))	{
X		nextblk();
X		return TRUE;
X	}
X	return FALSE;
X}
X
Xint
Xstrhead(s1, s2)
X	char *s1, *s2;
X{
X	while (*s1)
X		if (*s1++ != *s2++)
X			return FALSE;
X	return TRUE;
X}
X
Xread_tm()	{
X	if (bsize == 0)
X		nextblk();
X	else	{
X		print_loc();
X		printf("Tape mark missing\n");
X	}
X}
X
Xnextblk()	{
X
X	do bsize = tpread(tf, block, MAXBLK);
X	while (bsize > 0 && bsize < MINSIZE);
X}
X
Xint
Xinteresting(fn)
X	char *fn;
X{
X	char **lst = filelist, *nm;
X
X	if (lst == NULL)
X		return TRUE;
X	while ((nm = *lst++) != NULL)
X		if (strcmp(nm, fn) == 0)
X			return TRUE;
X	return FALSE;
X}
X
Xconv(addr, size)
X	char *addr;
X{
X	while (size-- > 0)	{
X		*addr = ebc2asc(*addr);
X		addr++;
X	}
X}
X
Xchar
Xasc2ebc(ch)
X	char ch;
X{
X	char ch1 = 0;
X
X	while (ch != ebc2asc(ch1))
X		ch1++;
X	return ch1;
X}
X
X/*
X * copy one file
X */
X
Xcopy()	{
X
X	init_copy();
X
X	do copypart();
X	while (change_tape());
X
X	end_copy();
X}
X
Xinit_copy()	{
X	int i;
X
X	blkcount = reccount = 0;
X	tot_uglies = 0L;
X	for (i = 0; i < n_items(uglies); i++)
X		uglies[i] = 0;
X
X	getpars();
X}
X
Xend_copy()	{
X
X	if (pflag && !skip_it)	{
X		printf("\n");
X		if (file != NULL)
X			printf("Record count: %d\n", reccount);
X		printf("Block count: %d\n", blkcount);
X		if (file != NULL)
X			prf_s("File copied: %s\n", filename);
X		else
X			printf("File skipped\n");
X	}
X
X	if (file != NULL)	{
X
X		VOID(fclose(file));
X		file = NULL;
X		if (tot_uglies != 0L)	{
X			int i;
X
X			print_loc();
X			printf("File contained %ld non-printing character%s:\n",
X				english(tot_uglies));
X			for (i = 0; i < n_items(uglies); i++)	{
X				int n = char2int(uglies[i]);
X
X				if (n != 0)	{
X					if (n <= MAXUGLY)
X						printf("%s: %d\n",
X							char2str(i), n);
X					else	printf("%s: >%d\n",
X							char2str(i), MAXUGLY);
X				}
X			}
X		}
X	}
X}
X
X/*
X * getpars sets `filename', `filecode', `recformat'
X * and as many further parameters as is necessary
X */
X
Xextern struct format fdummy;
X
Xgetpars()	{
X
X	if (nflag || skip_it)	{
X		recformat = &fdummy;
X		return;
X	}
X
X	inmood (!ok_fln ? ASK_YES : iflag ? ASK_SUG : ASK_NO)	{
X		strcpy(filename, enq_str("\
X	The `file name' is the name under which the tape file will be\n\
X	stored on disk. The named file must not already exist.\n\
X	Use a minus - to skip the file.\n",
X			mood, filename));
X
X		if (strcmp(filename, "-") == 0)	{
X			recformat = &fdummy;
X			return;
X		}
X		iferr (!isascstr(filename))	{
X			prf_s("Filename %s contains non-printing chars\n",
X				filename);
X			enderr;
X		}
X		iferr ((file = fopen(filename, "r")) != NULL)	{
X			prf_s("File %s already exists\n", filename);
X			VOID(fclose(file));
X			file = NULL;
X			enderr;
X		}
X		iferr ((file = fopen(filename, "w")) == NULL)	{
X			prf_s("Cannot create %s\n", filename);
X			enderr;
X		}
X		endmood;
X	}
X
X	inmood (	labcode == NULL && filecode == NULL ? ASK_YES :
X			labcode == NULL || iflag ? ASK_SUG : ASK_NO
X	)	{
X		filecode = enq_str("\
X	The `character code' is the code of the file on tape; it may be\n\
X	ASCII, EBCDIC (usual for IBM-tapes) or BINARY (no conversion).\n\
X	When in doubt, use %s.\n",
X			mood,
X			filecode != NULL ? filecode :
X			labcode != NULL ? labcode :
X			ascii);
X		switch (filecode[0])	{
X		case 'A':
X			filecode = ascii;
X			break;
X		case 'B':
X			filecode = binary;
X			break;
X		case 'E':
X			filecode = ebcdic;
X			break;
X		default:
X			printf("`%s' is not a character code\n", filecode);
X			filecode = NULL;
X		}
X		iferr (filecode == NULL)	{
X			printf("Specify %s, %s or %s\n",
X					ascii, ebcdic, binary);
X			enderr;
X		}
X		endmood;
X	}
X
X	if (filecode == binary)
X		strcpy(binrecsep,
X			enq_str("\
X	The `record separator' only applies to the character code\n\
X	BINARY, where it specifies what character(s) should be written\n\
X	to disk for each end-of-record on the tape. You will probably\n\
X	want it to be empty, but, when in doubt, try a recognizable\n\
X	string like }}}} and examine the results.\n",
X				ASK_SUG, binrecsep));
X
X	inmood (!ok_rct || jflag ? ASK_SUG : ASK_NO)	{
X		char *rct = enq_str("\
X	The `record format' tells how the block on tape must be cut into\n\
X	text records (lines). There are five standard ways to do so:\n\
X	F: each N consecutive characters form a record, where N is the\n\
X	   `record length',\n\
X	D: a header in each record tells its length,\n\
X	U: each block is one record,\n\
X	S: a special format in which records may be longer than blocks,\n\
X	V: IBM Variable format.\n\
X	When in doubt, use %s and examine the results, or try them all.\n",
X			mood, !ok_rct ? "U" : fld2str(Whole(rectype)));
X
X		iferr (	strlen(rct) != 1
X		||	(recformat = format_of_type(rct[0])) == NULL
X		)	{
X			printf("`%s' is not an ANSI format\n", rct);
X			printf("Please specify F, D, U, S or V\n");
X			enderr;
X		}
X		iferr (recformat->cpblk == NULL)	{
X			printf("%s-format not implemented\n", rct);
X			enderr;
X		}
X		str2fld(rct, Whole(rectype));
X		endmood;
X	}
X
X	inmood (!ok_blk || jflag ? ASK_SUG : ASK_NO)	{
X		blklength = enq_int("\
X	The `block length' is the maximum number of significant\n\
X	characters in any physical block (as demarcated by two\n\
X	interrecord gaps) on the tape.  Unless you know the exact value,\n\
X	use a large number like %s.\n",
X			mood, !ok_blk ? MAXBLK : blklength, MAXBLK);
X
X		iferr (blklength < MINSIZE)	{
X			printf("Block length cannot be smaller than %d\n",
X				MINSIZE);
X			enderr;
X		}
X		endmood;
X	}
X
X	(*recformat->checkpar)();
X
X	bufoffset = enq_int("\
X	The `buffer offset' is the position in each block on the tape at\n\
X	which the real information starts. Unless you know the exact\n\
X	value, use 0.\n",
X		!ok_bfo || jflag ? ASK_SUG : ASK_NO,
X		!ok_bfo ? 0 : bufoffset,
X		blklength - 1);
X}
X
Xcopypart()	{
X	while (bsize > 0)	{
X		int used;
X
X		++blkcount;
X		if (bsize > blklength)	{
X			print_loc();
X			printf("Actual block size = %d, not %d as in label\n",
X						bsize, blklength);
X		}
X		if (filecode == ebcdic)
X			conv(block, bsize);
X		used = bufoffset;
X		used += (*recformat->cpblk) (&block[used], bsize-used);
X		if (!filler(&block[used], bsize-used))	{
X			print_loc();
X			printf("At block %d, after record %d:",
X				blkcount, reccount);
X			printf(" %d char%s garbage ignored\n",
X					english(bsize-used));
X		}
X		nextblk();
X	}
X	read_tm();
X}
X
Xint
Xchange_tape()	{
X	return FALSE;	/* not yet implemented */
X}
X
XcheckF()	{
X
X	inmood (!ok_rec || jflag ? ASK_SUG : ASK_NO)	{
X		reclength = enq_int("\
X	The `record length' is a number N such that a <newline> is\n\
X	assumed after each N characters read from tape. When in doubt,\n\
X	use %s and examine the results for a better value.\n",
X			mood,
X			!ok_rec || blklength < reclength ?
X				blklength : reclength,
X			blklength);
X
X		iferr (reclength == 0)	{
X			printf("Record length cannot be zero\n");
X			enderr;
X		}
X		endmood;
X	}
X}
X
X
Xint
XcpFblk(buf, size)
X	char *buf;
X{
X	int i = 0;
X
X	while (i <= size - reclength)	{
X		char *rec = &buf[i];
X		int sz = reclength;
X
X		reccount++;
X		if (filecode != binary)	{
X			char pad = rec[sz-1];
X
X			if (!is_ascii95(pad) || pad == SP)	/* liberal */
X				while (sz > 0 && rec[sz-1] == pad)
X					sz--;
X		}
X		put_rec(rec, sz);
X		put_eor();
X		i += reclength;
X	}
X	return i;
X}
X
Xint
XcpUblk(buf, size)
X	char *buf;
X{
X	reccount++;
X	put_rec(buf, size);
X	put_eor();
X	return size;
X}
X
X#define	DVPREF	4	/* size of D or V length prefix */
X
Xint
XcpDVblk(buf, size)
X	char *buf;
X{
X	int i = rectype[0] == 'V' ? DVPREF : 0;
X
X	while (size - i >= DVPREF)	{
X		char *rec = &buf[i];
X		int sz = DVlength(rec);
X
X		if (sz < DVPREF || size - i - sz < 0)
X			break;
X
X		reccount++;
X		put_rec(rec + DVPREF, sz - DVPREF);
X		put_eor();
X		i += sz;
X	}
X	return i;
X}
X
Xint
XDVlength(buf)
X	char *buf;
X{
X	int res = 0;
X
X	if (rectype[0] == 'V')	{
X		int i;
X		for (i = 0; i <= 1; i++)	{
X			char ch = buf[i];
X			res = res*256 +
X				char2int(filecode == ebcdic ?
X							asc2ebc(ch) : ch);
X		}
X	}
X	else
X		res = fld2int(buf, DVPREF);
X	return res;
X}
X
X#define	SPREF	5	/* size of S length prefix */
X
Xint
XcpSblk(buf, size)
X	char *buf;
X{
X	int i = 0;
X
X	while (size - i >= SPREF)	{
X		char *rec = &buf[i];
X		char ind = rec[0];
X		int sz = fld2int(rec+1, SPREF-1);
X
X		if (sz < SPREF || size - i - sz < 0)
X			break;
X
X		if (ind == '0' || ind == '1')
X			reccount++;
X		put_rec(rec + SPREF, sz - SPREF);
X		if (ind == '0' || ind == '3')
X			put_eor();
X		i += sz;
X	}
X	return i;
X}
X
Xskip()	{
X	return;
X}
X
Xint
Xskpblk(buf, size)
X	char *buf;
X{
X	VOID(buf);
X	return size;
X}
X
Xint
Xfiller(addr, size)
X	char *addr;
X{
X	char ch = *addr;
X
X	while (size--)
X		if (ch != *addr++)
X			return FALSE;
X	return TRUE;
X}
X
Xstruct format formats[] =	{
X	{'F', checkF, cpFblk},
X	{'U', skip, cpUblk},
X	{'D', skip, cpDVblk},
X	{'V', skip, cpDVblk},	/* to cater for you know whom */
X	{'S', skip, cpSblk},
X	{EOS, NULL, NULL}
X};
X
Xstruct format fdummy =	{EOS, skip, skpblk};
X
Xput_rec(rec, size)
X	char *rec;
X{
X	int i;
X
X	for (i = 0; i < size; i++)	{
X		int ch = char2int(rec[i]);
X
X		if (filecode == binary || is_ascii95(ch))
X			putc(ch, file);
X		else	{
X			fprintf(file, "%s", char2str(ch));
X			if (uglies[ch] <= MAXUGLY)
X				uglies[ch]++;
X			tot_uglies++;
X		}
X	}
X}
X
Xput_eor()	{
X	char *sep = filecode == binary ? binrecsep : CRECSEP;
X	char ch;
X
X	while ((ch = *sep++) != EOS)
X		putc(ch, file);
X}
X
X/*
X * Reads the EOF1-label and checks block count
X */
X
XlblEOF1()	{
X	int bcount;
X	int found = label("EOF1", Whole(HDR1buf));
X
X	if (skip_it)
X		return;
X
X	if (!found)	{
X		missing("EOF1");
X		return;
X	}
X
X	bcount = fld2int(Blkcount(HDR1buf));
X
X	if (pflag)
X		prHDR1();
X
X	if (HDR1blc >= 0 && bcount != blkcount + HDR1blc)	{
X		print_loc();
X		printf(
X		"File holds %d block%s whereas labels report %d block%s\n",
X			english(blkcount), english(bcount - HDR1blc));
X	}
X}
X
X/*
X * Read EOF2-label
X */
X
XlblEOF2()	{
X	int found = label("EOF2", Whole(HDR2buf));
X
X	if (skip_it)
X		return;
X
X	if (!found)	{
X		missing("EOF2");
X		return;
X	}
X
X	if (pflag)
X		prHDR2();
X}
X
X/*
X * Print routines
X */
X
XprVOL1()	{
X	prhead(Labidf(VOL1buf));
X	printf("The labels are in %s\n", labcode);
X	prfield("Volume serial number", Volidf(VOL1buf));
X	prfield("Volume accessibility", Volacc(VOL1buf));
X	prunused(Sp1(VOL1buf));
X	prfield("Owner identification", Ownidf(VOL1buf));
X	prunused(Sp2(VOL1buf));
X	prfield("Label version", Labvers(VOL1buf));
X}
X
XprHDR1()	{
X	prhead(Labidf(HDR1buf));
X	prfield("File identifier", Fileidf(HDR1buf));
X	prfield("Set identifier", Filesetidf(HDR1buf));
X	prfield("File section number", Filsecnum(HDR1buf));
X	prfield("File sequence number", Filseqnum(HDR1buf));
X	if (gflag)	{
X		prfield("Generation number", Gennum(HDR1buf));
X		prfield("Generation version number", Genversnum(HDR1buf));
X	}
X	prfield("Creation date", Creatdate(HDR1buf));
X	prfield("Expiration date", Expirdate(HDR1buf));
X	prfield("File accessibility", Fileacc(HDR1buf));
X	prfield("Block count", Blkcount(HDR1buf));
X	prfield("System code", Syscode(HDR1buf));
X	prunused(Sp3(HDR1buf));
X}
X
XprHDR2()	{
X	prhead(Labidf(HDR2buf));
X	prfield("Record format", Recformat(HDR2buf));
X	prfield("Block length", Blklength(HDR2buf));
X	prfield("Record length", Reclength(HDR2buf));
X	prfield("System software", Syssoftw(HDR2buf));
X	prfield("Buffer offset", Bufoffset(HDR2buf));
X	prunused(Sp4(HDR2buf));
X}
X
Xprhead(addr, size)
X	char *addr;
X{
X	printf("\nInformation from the %s-label\n", fld2str(addr, size));
X}
X
Xprfield(nm, addr, size)
X	char *nm, *addr;
X{
X	char *str = fld2str(addr, size);
X
X	printf("%s: ", nm);
X	prf_s("%s\n", *str == EOS ? sps2txt(size) : str);
X}
X
Xprunused(addr, size)
X	char *addr;
X{
X	char *str = fld2str(addr, size);
X
X	if (strlen(str) > 0)
X		prf_s("Unused field: %s\n", str);
X}
X
Xmissing(idf)
X	char *idf;
X{
X	print_loc();
X	printf("%s-label missing\n", idf);
X}
X
Xint
Xchk_int(nm, val)
X	char *nm;
X{
X		if (val < 0)	{
X			print_loc();
X			printf("Garbage in %s field\n", nm);
X			return FALSE;
X		}
X		else
X			return TRUE;
X}
X
Xprint_loc()	{
X
X	if (ok_loc || pflag)
X		return;
X	if (ok_fln)
X		prf_s("\n*** At file `%s':\n", filename);
X	else
X		printf("\n*** At file number %d:\n", filseqnum);
X	ok_loc = TRUE;
X}
+ END-OF-FILE ansir.c
chmod 'u=rw,g=r,o=r' \a\n\s\i\r\.\c
set `sum \a\n\s\i\r\.\c`
sum=$1
case $sum in
51802)	:;;
*)	echo 'Bad sum in '\a\n\s\i\r\.\c >&2
esac
echo Extracting \a\n\s\i\w\.\c
sed 's/^X//' > \a\n\s\i\w\.\c << '+ END-OF-FILE '\a\n\s\i\w\.\c
X/*	This file is part of the magtape handling package MAG.
X	Written by Dick Grune, Vrije Universiteit, Amsterdam.
X*/
X
X/*
X * Name: ansiw, write ANSI standard labelled tape
X * Version: 820314
X */
X
X#define	MSGUSE	"Usage: ansiw [-cfhlmignpv] [ file ... ]"
X
X#include	"aux.h"
X#include	"sys.h"
X#include	"tp.h"
X#include	"tploc.h"		/* to get SYSCODE */
X#include	"ansi.h"
X
X#define	MAXBLK	2048
X#define	MINBLK	18
X#define	FILLER	'^'
X
Xchar iflag = FALSE, gflag = FALSE, pflag = FALSE, vflag = FALSE;
Xchar block[MAXBLK];
X
Xstruct DD	{
X	long size;
X	long lrecl;
X	char ascii95;
X	char example;
X} dd;
Xstruct DD empty_dd =	{0L, 0L, TRUE, EOS};
X
X#define	divis(m, n)	((n)!=0&&(m)%(n)==0)
X
Xmain(argc, argv)
X	int argc;
X	char *argv[];
X{
X	argc--, argv++;
X	while (argc > 0 && argv[0][0] == '-')	{
X		char *pp = argv[0];
X		
X		while (*++pp)	{
X			switch (*pp)	{
X			/* insert cases to handle the standard options */
X#include	"options.h"
X			/* special options */
X			case 'g':
X				gflag = TRUE;
X				break;
X			case 'i':
X				iflag = TRUE;
X				break;
X			case 'n':
X				unit = TP_IMAG;
X				nmdns = "/dev/null";
X				break;
X			case 'p':
X				pflag = TRUE;
X				break;
X			case 'v':
X				vflag = TRUE;
X				break;
X			}
X		}
X		argc--, argv++;
X	}
X	tf = tpopen(unit, nmdns, "w");
X
X	check_args(argc, argv);
X
X	lblVOL1(iflag || vflag ? ASK_SUG : ASK_NO);
X
X	while (argc-- != 0)	{
X		strcpy(filename, argv[filseqnum]);
X		filseqnum++;
X		blkcount = 0;
X
X		opendd(filename);
X		if (file == NULL)	{
X			printf(">>> File %s ", filename);
X			errors("has suddenly disappeared!!!");
X		}
X		lblHDR1(iflag ? ASK_SUG : ASK_NO);
X		lblHDR2(iflag ? ASK_SUG : ASK_NO);
X		wrt_tm();
X		copy();
X		wrt_tm();
X		lblEOF1();
X		lblEOF2();
X		wrt_tm();
X	}
X
X	wrt_tm();
X	tpclose(tf);
X	exit(0);
X
XLbad:
X	errors(MSGUSE);
X	exit(1);
X}
X
Xcheck_args(c, v)
X	char *v[];
X{
X	char ok = TRUE;
X
X	while (c-- > 0)	{
X		int f = open(*v, 0);
X
X		if (f < 0)	{
X			printf("Cannot open %s\n", *v);
X			ok = FALSE;
X		}
X		else	VOID(close(f));
X		v++;
X	}
X	if (!ok)
X		errors("Stop");
X}
X
Xwrt_tm()
X{	/* writes a tapemark */
X	tpwrite(tf, "", 0);
X}
X
Xlong
Xtab(p)
X	long p;		/* the position in which a tab from p would land */
X{
X	return (p/8+1)*8;
X}
X
X/*
X * `opendd' opens the file `fn' and determines its `dd' parameters
X */
X
Xopendd(fn)
X	char *fn;
X{
X	int ch;
X	long lr;
X
X	dd = empty_dd;
X	if ((file = fopen(fn, "r")) == NULL)
X		return;
X
X	lr = 0L;
X	while ((ch = getc(file)) != EOF)	{
X		dd.size++;
X		if (ch == NL)	{
X			if (lr > dd.lrecl)
X				dd.lrecl = lr;
X			lr = 0L;
X		}
X		else
X		if (ch == TAB)	{
X			lr = tab(lr);
X		}
X		else	{
X			lr++;
X			if (!is_ascii95(ch))	{
X				dd.ascii95 = FALSE;
X				dd.example = ch;
X			}
X		}
X	}
X	if (lr > dd.lrecl)
X		dd.lrecl = lr;
X
X	VOID(fclose(file));
X	file = fopen(fn, "r");
X}
X
X/*
X * the writing of labels
X */
X
XlblVOL1(md)	{
X	char *owner = username();
X	
X	str2fld("", Whole(VOL1buf));
X	str2fld("VOL1", Labidf(VOL1buf));
X
X	enq_fld("\
X	The `volume serial number' is the six-character identification\n\
X	number of the tape itself, as it should appear on the sticker on\n\
X	the reel. When in doubt, use the default %s.\n",
X		md, "222222", Volidf(VOL1buf));
X	enq_fld("\
X	The `volume accessibility symbol' is a single character,\n\
X	recorded on the tape, which indicates how publicly accessible the\n\
X	whole tape is. It is not well defined, but a single space is\n\
X	generally taken to mean: accessible by anybody.\n",
X		md, " ", Volacc(VOL1buf));
X	enq_fld("\
X	The `owner identification' is the name of the owner, as recorded\n\
X	on the tape. On some systems it interacts with the file\n\
X	accessibility symbol. When in doubt, specify a short string of\n\
X	letters.\n",
X		owner == NULL ? ASK_YES : md, owner, Ownidf(VOL1buf));
X	str2fld("1", Labvers(VOL1buf));
X
X	tpwrite(tf, Whole(VOL1buf));
X}
X
XlblHDR1(md)	{
X	char *today = sysdate();
X	
X	str2fld("", Whole(HDR1buf));
X	str2fld("HDR1", Labidf(HDR1buf));
X	enq_fld("\
X	The `file identifier' is the name of the file, as recorded on\n\
X	the tape.  When in doubt, specify a six-letter mnemonic name.\n",
X		md, filename, Fileidf(HDR1buf));
X
X	fld2fld(Volidf(VOL1buf), Filesetidf(HDR1buf));
X	int2fld(filsecnum, Filsecnum(HDR1buf));
X	int2fld(filseqnum, Filseqnum(HDR1buf));
X	enq_num("\
X	The `generation number' is a counter that some operating systems\n\
X	attach to a file and that is increased each time the file is\n\
X	updated. Use 1.\n",
X		gflag ? md : ASK_NO, 1, Gennum(HDR1buf));
X	enq_num("\
X	The `generation version number' tells how often an attempt to\n\
X	write the file to tape has failed. Use 0.\n",
X		gflag ? md : ASK_NO, 0, Genversnum(HDR1buf));
X	dat2fld(today, Creatdate(HDR1buf));
X	enq_dat("\
X	The `expiration date' is the date, recorded on the tape, after\n\
X	which the file may be overwritten. The format is 2 digits for\n\
X	the year, followed by 3 digits for the day in the year, e.g.,\n\
X	86365 for the last day of 1986.  When in doubt, use today's date,\n\
X	%s, to make the receiver's life easier.\n",
X		md, today, Expirdate(HDR1buf));
X	enq_fld("\
X	The `file accessibility symbol' is a single character, recorded\n\
X	on the tape, which indicates how publicly accessible the file is.\n\
X	It is not well defined, but a single space is generally taken to\n\
X	mean: accessible by anybody.\n",
X		md, " ", Fileacc(HDR1buf));
X	int2fld(blkcount, Blkcount(HDR1buf));
X
X	str2fld(SYSCODE /* from tploc.h */, Syscode(HDR1buf));
X
X	tpwrite(tf, Whole(HDR1buf));
X}
X
XlblHDR2(md)	{
X
X	str2fld("", Whole(HDR2buf));
X	str2fld("HDR2", Labidf(HDR2buf));
X
X	if (!iflag)	{
X		str2fld("F", Whole(rectype));
X		blklength = 1920;
X		reclength = 80;
X	}
X
X	if (!dd.ascii95)	{
X		printf("`%s' contains non-ASCII95 characters, e.g., %s\n",
X			filename, char2str(dd.example));
X		printf("Perhaps the file code should have been BINARY");
X		str2fld("U", Whole(rectype));
X	}
X
X	if (dd.lrecl > MAXBLK)	{
X		printf("`%s' has a record length > %d\n", filename, MAXBLK);
X		printf("Only U-format is possible\n");
X		str2fld("U", Whole(rectype));
X		recformat = format_of_type('U');
X	}
X	else
X	inmood (!dd.ascii95 ? ASK_SUG : md)	{
X		char *rct = enq_str("\
X	The `record format' tells how lines from the disk file should be\n\
X	converted to records to be packed into blocks to be recorded on\n\
X	tape. Although many formats exist, only two are any good in\n\
X	Information Interchange:\n\
X	F (Fixed): spaces are added at the end of the line until its\n\
X	    length is `record length', and `block length'/`record length'\n\
X	    of these records form a block;\n\
X	U (Undefined): `block length' characters are stored in a block.\n\
X	Unless the disk file contains non-ASCII characters, use F.\n",
X			mood, fld2str(Whole(rectype)));
X
X		iferr (	strlen(rct) != 1
X		||	(recformat = format_of_type(rct[0])) == NULL
X		||	recformat->cpblk == NULL
X		)	{
X			printf(
X			"Only F- and U-formats are allowed for portability\n"
X			);
X			enderr;
X		}
X
X		str2fld(rct, Whole(rectype));
X		endmood;
X	}
X
X	(*recformat->checkpar)(md);
X
X	fld2fld(Whole(rectype), Recformat(HDR2buf));
X	int2fld(blklength, Blklength(HDR2buf));
X	int2fld(reclength, Reclength(HDR2buf));
X	int2fld(bufoffset, Bufoffset(HDR2buf));
X
X	tpwrite(tf, Whole(HDR2buf));
X}
X
XcheckF(md)	{
X	int lr;
X
X	inmood (md)	{
X		getBlklength(mood);
X		iferr (blklength < reclength)	{
X			printf("Block length < phys. record length (=%ld)\n",
X				dd.lrecl);
X			enderr;
X		}
X		endmood;
X	}
X
X	lr = dd.lrecl;
X	while (!divis(blklength, lr))
X		lr++;
X	if (lr < 80 && divis(blklength, 80))
X		lr = 80;
X	reclength = lr;
X
X	inmood (md)	{
X		reclength = enq_int("\
X	The `record length' is the number of characters into which each\n\
X	line (record) is stretched before it is written to tape. It must\n\
X	divide the block length. Unless the receiver has been very\n\
X	specific, use %s.\n",
X			mood, reclength, blklength);
X		iferr (reclength == 0 || !divis(blklength, reclength))	{
X			printf(
X		"The block length is not a multiple of the record length\n"
X			);
X			enderr;
X		}
X		iferr (reclength < dd.lrecl)	{
X			printf("Record length < phys. record length (=%ld)\n",
X				dd.lrecl);
X			enderr;
X		}
X		endmood;
X	}
X}
X
XcheckU(md)	{
X	getBlklength(md);
X	reclength = blklength;
X}
X
XgetBlklength(md)	{
X	inmood (md)	{
X		blklength =
X			enq_int("\
X	The `block length' is the number of characters in each physical\n\
X	block written to tape. Unless the receiver has specified\n\
X	something else, use %s.\n",
X				mood,
X				(rectype[0] == 'F' && dd.lrecl > 1920) ?
X					MAXBLK : !iflag ? 1920 : blklength,
X				MAXBLK);
X		iferr (blklength < MINBLK)	{
X			printf("The minimum block length is %d\n", MINBLK);
X			enderr;
X		}
X		endmood;
X	}
X}
X
X
XlblEOF1()	{
X	str2fld("EOF1", Labidf(HDR1buf));
X	int2fld(blkcount, Blkcount(HDR1buf));
X	tpwrite(tf, Whole(HDR1buf));
X}
X
XlblEOF2()	{
X	str2fld("EOF2", Labidf(HDR2buf));
X	tpwrite(tf, Whole(HDR2buf));
X}
X
X/*
X * the copying of the file
X */
X
Xcopy()	{
X	int size;
X
X	blkcount = reccount = 0;
X
X	while ((size = (*recformat->cpblk)()) > 0)	{
X		while (size < MINBLK)
X			block[size++] = FILLER;
X		tpwrite(tf, block, size);
X		++blkcount;
X	}
X	VOID(fclose(file));
X	file = NULL;
X	if (pflag)	{
X		printf("File name: %s\n", filename);
X		printf("Record format: %s\n", rectype);
X		printf("Block length: %d; number of blocks: %d\n",
X			blklength, blkcount);
X		printf("Record length: %d; number of records: %d\n\n",
X			reclength, reccount);
X	}
X}
X
Xint
XcpFblk()	{
X	int ch;
X	int count = 0;
X
X	while (count < blklength && (ch = getc(file)) != EOF)	{
X		int rpos = 0;
X		reccount++;
X		while (ch != NL && ch != EOF)	{
X			if (ch == TAB)	{
X				int nrpos = (int)tab((long)rpos);
X				while (rpos < nrpos)	{
X					block[count++] = SP, rpos++;
X				}
X			}
X			else	{
X				block[count++] = ch, rpos++;
X			}
X			ch = getc(file);
X		}
X		while (rpos < reclength)	{
X			block[count++] = SP, rpos++;
X		}
X	}
X	return count;
X}
X
Xint
XcpUblk()	{
X	int ch;
X	int count = 0;
X
X	while (count < blklength && (ch = getc(file)) != EOF)	{
X		block[count++] = ch;
X	}
X	if (count > 0)
X		reccount++;
X	return count;
X}
X
Xstruct format formats[] =	{
X	{'F', checkF, cpFblk},
X	{'U', checkU, cpUblk},
X	{'D', NULL, NULL},
X	{'S', NULL, NULL},
X	{EOS, NULL, NULL}
X};
X
X/*
X * the setting of fields
X */
X
Xint2fld(n, addr, size)
X	char *addr;
X{
X	addr += size;
X	while (size-- > 0)	{
X		*--addr = n % 10 + '0';
X		n = n / 10;
X	}
X}
X
Xdat2fld(str, addr, size)
X	char *str, *addr;
X{
X	str2fld("", addr, size);
X	str2fld(str, Date(addr));
X}
X
Xenq_fld(expl, md, def, addr, size)
X	char *expl, *def, *addr;
X{
X	char *ans;
X	
X	inmood (md)	{
X		ans = enq_str(expl, mood, def);
X		iferr (strlen(ans) == 0)	{
X			printf("No empty answer allowed\n");
X			enderr;
X		}
X		iferr (strlen(ans) > size)	{
X			printf("The %s is too long\n", expl2str(expl));
X			printf("The maximum length is %d character%s\n",
X				english(size));
X			enderr;
X		}
X		iferr (!isascstr(ans))	{
X			printf("The %s `%s' contains non-printing chars\n",
X				expl2str(expl), ans);
X			enderr;
X		}
X		endmood;
X	}
X	str2fld(ans, addr, size);
X}
X
Xenq_dat(expl, md, def, addr, size)
X	char *expl, *def, *addr;
X{
X	dat2fld(def, addr, size);
X	inmood (md)	{
X		int yd;
X		
X		enq_fld(expl, mood, def, Date(addr));
X		iferr (fld2int(Yr(addr)) < 0)	{
X			printf("Year must be numeric\n");
X			enderr;
X		}
X		yd = fld2int(Yd(addr));
X		iferr (yd < 1 || yd > 366)	{
X			printf("Date in year must be between 1 and 366\n");
X			enderr;
X		}
X		endmood;
X	}
X}
X
Xenq_num(expl, md, def, addr, size)
X	char *expl, *addr;
X{
X	int2fld(enq_int(expl, md, def, tento(size)-1), addr, size);
X}
X
Xint
Xtento(n)	{
X	int res = 1;
X
X	while (n--)
X		res *= 10;
X	return res;
X}
X
Xprint_loc()	{
X	/* dummy in ansiw.c; useful in ansir.c */
X	return;
X}
+ END-OF-FILE ansiw.c
chmod 'u=rw,g=r,o=r' \a\n\s\i\w\.\c
set `sum \a\n\s\i\w\.\c`
sum=$1
case $sum in
35905)	:;;
*)	echo 'Bad sum in '\a\n\s\i\w\.\c >&2
esac
echo Extracting \c\p\t\p\.\c
sed 's/^X//' > \c\p\t\p\.\c << '+ END-OF-FILE '\c\p\t\p\.\c
X/*	This file is part of the magtape handling package MAG.
X	Written by Dick Grune, Vrije Universiteit, Amsterdam.
X*/
X
X/*
X * Name: cptp, copy tape
X * Version: 820314
X *
X * `Cptp' converts between real tapes and tape images on disk.
X */
X
X#define	MSGUSE	"Usage is: cptp [-cfhlmx] [of=file | if=file]"
X
X#include	<stdio.h>
X#include	"aux.h"
X#include	"tp.h"
X
Xint unit = 0;
Xchar *nmdns = TP_DENN;
Xchar *rx = "r";
XTPFILE *from, *to;
Xchar *filename;
Xint size;
Xchar buff[TP_MAXB];
X
Xmain(argc, argv)
X	char *argv[];
X{
X	char *arg;
X
X	argc--, argv++;
X	while (argc > 0 && argv[0][0] == '-')	{
X		char *pp = argv[0];
X		
X		while (*++pp)	{
X			switch (*pp)	{
X			/* insert cases to handle the standard options */
X#include	"options.h"
X			/* special options */
X			case 'x':
X				rx = "rx";
X				break;
X			}
X		}
X		argc--, argv++;
X	}
X	if (argc != 1)
X		goto Lbad;
X	arg = argv[0];
X	if (arg[0] == '\0' || arg[1] != 'f' || arg[2] != '=')
X		goto Lbad;
X	filename = &arg[3];
X	
X	tperrout(stdout);
X	switch (arg[0])	{
X	case 'o':
X		if (open(filename, 0) > 0)
X			error("Output file already exists");
X		from = tpopen(unit, nmdns, rx);
X		to = tpopen(TP_IMAG, filename, "w");
X		break;
X	case 'i':
X		from = tpopen(TP_IMAG, filename, "r");
X		to = tpopen(unit, nmdns, "w");
X		break;
X	default:
X		goto Lbad;
X	}
X
X	while ((size = tpread(from, buff, TP_MAXB)) >= 0)	{
X		if (size == TP_MAXB)
X			printf("Block too long; information may be lost\n");
X		tpwrite(to, buff, size);
X	}
X	tpclose(from);
X	tpclose(to);
X	exit(0);
X
XLbad:
X	error(MSGUSE);
X	exit(1);
X}
X
Xerror(str)
X	char *str;
X{
X	fprintf(stderr, "%s\n", str);
X	exit(1);
X}
+ END-OF-FILE cptp.c
chmod 'u=rw,g=r,o=r' \c\p\t\p\.\c
set `sum \c\p\t\p\.\c`
sum=$1
case $sum in
62900)	:;;
*)	echo 'Bad sum in '\c\p\t\p\.\c >&2
esac
echo Extracting \r\a\w\t\p\.\c
sed 's/^X//' > \r\a\w\t\p\.\c << '+ END-OF-FILE '\r\a\w\t\p\.\c
X/*	This file is part of the magtape handling package MAG.
X	Written by Dick Grune, Vrije Universiteit, Amsterdam.
X*/
X
X/*
X * Name: rawtp, read raw tape
X * Version: 820314
X *
X   Selected portions are read from tape and written to files.
X
X*/
X
X#define	MSGUSE	"Usage is: rawtp [-cfhlmx] XX [ param ... ]"
X
X#include	<stdio.h>
X#include	"aux.h"
X#include	"tp.h"
X
X#define	TRUE	1
X#define	FALSE	0
X#define	EOS	'\0'
X
X#define	EOB	0	/* End Of Block */
X#define	EOX	-1	/* End Of File (to avoid confusion with EOF) */
X#define	EOT	-2	/* End Of Tape */
X#define	AT_EOB	(ilength <= EOB)
X#define	AT_EOX	(ilength <= EOX)
X#define	AT_EOT	(ilength <= EOT)
X
Xchar name [128];
Xchar *eoname = &name[0];
XFILE *ofile = NULL;
X
XTPFILE *tape;
Xint unit = 0;
Xchar *nmdns = TP_DENN;
Xchar *rx = "r";
Xchar buff[TP_MAXB];
X
Xchar *strins();
X
Xmain(argc, argv)
X	char **argv;
X{
X	extern int ilength;
X
X	argc--, argv++;
X	while (argc > 0 && argv[0][0] == '-')	{
X		char *pp = argv[0];
X		
X		while (*++pp)	{
X			switch (*pp)	{
X			/* insert cases to handle the standard options */
X#include	"options.h"
X			/* special options */
X			case 'x':
X				rx = "rx";
X				break;
X			}
X		}
X		argc--, argv++;
X	}
X	if (argc < 1)
X		goto Lbad;
X	if (**argv == '+' || **argv == '-')
X		goto Lbad;
X	set_name(argv);
X	argc--, argv++;
X
X	ilength = EOT;	/* fake empty tape to test parameters */
X	params(argc, argv);
X
X	tperrout(stdout);
X	tape = tpopen(unit, nmdns, rx);
X	ilength = EOB;	/* and now for keeps */
X	skipIRG();
X	params(argc, argv);
X	tpclose(tape);
X	exit(0);
X
XLbad:
X	error(MSGUSE, "");
X	exit(1);
X}
X
Xset_name(argv)
X	char **argv;
X{
X	register char *pt;
X
X	eoname = strins(eoname, *argv);
X	eoname = strins(eoname, "01aaa01");
X	*eoname = EOS;
X	for (pt = eoname; pt > name; pt--)
X		if (pt[-1] == '/') break;
X	if (eoname - pt > 14)
X		error("%s: file name too long", name);
X}
X
Xparams(argc, argv)
X	char **argv;
X{
X	VOID(strins(eoname-7, "01"));
X	if (!argc)
X		param("+1x");
X	else
X		while (argc--)	{
X			param(*argv++);
X			incr(eoname-6);
X		}
X}
X
Xchar *ppar;	/* parameter being processed */
X
Xparam(arg)
X	char *arg;
X{
X	register int repl;
X
X	ppar = arg;
X	repl = getxrepl(ppar);
X	if (repl == 0) repl--;
X	VOID(strins(eoname-5, "aaa"));
X	while (repl-- && instr())
X		incr(eoname-3);
X}
X
Xint moved;
X
Xint
Xinstr()	{
X	char *p = ppar;
X
X	moved = FALSE;
X	VOID(strins(eoname-2, "01"));
X	while (simp_instr(&p))
X		incr(eoname-1);
X	return moved;
X}
X
Xint copy = FALSE;
X
Xint
Xsimp_instr(pp)
X	char **pp;
X{
X	register int cnt;
X
X	switch (**pp)	{
X	case EOS:
X	case 'x':
X		return FALSE;
X	case '+':
X		copy = TRUE;
X		break;
X	case '-':
X		copy = FALSE;
X		break;
X	default:
X		error("%s: bad parameter", ppar);
X	}
X	(*pp)++;
X	cnt = getint(pp);
X	while (cnt-- && copyfile())	{
X	}
X	if (**pp == '.')
X		(*pp)++;
X	cnt = getint(pp);
X	while (cnt-- && copyblock())	{
X	}
X	if (**pp == '.')
X		(*pp)++;
X	cnt = getint(pp);
X	while (cnt-- && copychar())	{
X	}
X	if (copy)
X		dropfile();
X	return TRUE;
X}
X
Xint ilength;
X
X/* ilength contains the number of characters the tape is ahead of the user;
X * or it is EOX or EOT
X */
Xchar *iptr;
X
Xint
Xcopyfile()	{
X
X	if (AT_EOT)
X		return FALSE;
X	while (copyblock())	{}
X	skipTM();
X	return TRUE;
X}
X
Xint
Xcopyblock()	{
X
X	if (AT_EOX)
X		return FALSE;
X	if (!copy)
X		ilength = EOB;
X	else
X		while (copychar())	{}
X	skipIRG();
X	return TRUE;
X}
X
Xint
Xcopychar()	{
X
X	if (AT_EOB)
X		return FALSE;
X	outchar(*iptr);
X	iptr++;
X	ilength--;
X	return TRUE;
X}
X
Xoutchar(c)	{
X
X	if (!copy)
X		return;
X	if (ofile == NULL)	{
X		getfile();
X		moved = TRUE;
X	}
X	putc(c, ofile);
X}
X
X/* physical tape movers */
X
XskipTM()	{
X
X	if (AT_EOT)
X		return;
X	ilength = EOB;
X	skipIRG();
X}
X
XskipIRG()	{
X	int size;
X
X	if (AT_EOX)
X		return;
X	size = tpread(tape, buff, TP_MAXB);
X	ilength = size < 0 ? EOT : size == 0 ? EOX : size;
X	iptr = buff;
X	if (!AT_EOT)
X		moved = TRUE;
X}
X
X/* output file registration */
X
Xgetfile()	{
X
X	if ((ofile = fopen(name, "w")) == NULL)
X		error("%s: cannot create", name);
X}
X
Xdropfile()	{
X
X	if (ofile != NULL)	{
X		VOID(fclose(ofile));
X		ofile = NULL;
X	}
X}
X
X/* service routines */
X
Xchar *
Xstrins(s1, s2)
X	char *s1, *s2;
X{
X	while (*s2 != EOS)
X		*s1++ = *s2++;
X	return s1;
X}
X
Xint
Xgetint(pp)
X	char **pp;
X{
X	register int val, res = 0;
X
X	for (;;)	{
X		val = **pp - '0';
X		if (val < 0 || val > 9)
X			return res;
X		(*pp)++;
X		res = res*10 + val;
X	}
X}
X
Xincr(p)
X	char *p;
X{
X	(*p)++;
X	if (*p == '9' + 1)	{
X		*p = '0';
X		incr(p-1);
X	}
X	else
X	if (*p == 'z' + 1)	{
X		*p = 'a';
X		incr(p-1);
X	}
X}
X
Xint
Xgetxrepl(p)
X	char *p;
X{
X	register int r;
X
X	while (*p != 'x')
X		if (!*p++)
X			return 1;
X	p++;
X	r = getint(&p);
X	if (*p)
X		error("%s: bad replicator", p);
X	return r;
X}
X
Xerror(p1, p2)
X	char *p1, *p2;
X{
X	printf(p1, p2);
X	printf("\n");
X	exit(1);
X}
+ END-OF-FILE rawtp.c
chmod 'u=rw,g=r,o=r' \r\a\w\t\p\.\c
set `sum \r\a\w\t\p\.\c`
sum=$1
case $sum in
43915)	:;;
*)	echo 'Bad sum in '\r\a\w\t\p\.\c >&2
esac
echo Extracting \s\u\r\v\e\y\.\c
sed 's/^X//' > \s\u\r\v\e\y\.\c << '+ END-OF-FILE '\s\u\r\v\e\y\.\c
X/*	This file is part of the magtape handling package MAG.
X	Written by Dick Grune, Vrije Universiteit, Amsterdam.
X*/
X
X/*
X * Name: survey, survey contents of magtape
X * Version: 820314
X */
X
X#define	MSGUSE	"Usage is: survey [-cfhlmpx]\n"
X
X#include	<stdio.h>
X#include	"aux.h"
X#include	"tp.h"
X#include	"etoa.h"
X
X#define	WIDTH	64
X
Xint unit = 0;
Xchar *nmdns = TP_DENN;
Xchar *rx = "r";
XTPFILE *tf;
Xchar buff[TP_MAXB];
Xint size;
X
Xchar pflag = 0;
X
Xmain(argc, argv)
X	char *argv[];
X{
X	argc--, argv++;
X	while (argc > 0 && argv[0][0] == '-')	{
X		char *pp = argv[0];
X		
X		while (*++pp)	{
X			switch (*pp)	{
X			/* insert cases to handle the standard options */
X#include	"options.h"
X			/* special options */
X			case 'p':
X				pflag = 1;
X				break;
X			case 'x':
X				rx = "rx";
X				break;
X			}
X		}
X		argc--, argv++;
X	}
X
X	if (argc != 0)
X		goto Lbad;
X
X	tf = tpopen(unit, nmdns, rx);
X
X	while ((size = tpread(tf, buff, TP_MAXB)) >= 0)	{
X		printf("%6d", size);
X		if (pflag)
X			expose();
X		printf("\n");
X	}
X	exit(0);
X
XLbad:
X	fprintf(stderr, MSGUSE);
X	exit(1);
X}
X
Xint
Xhex(ch)	{
X	return "0123456789ABCDEF"[ch&017];
X}
X
Xint
Xprintable(ch)
X	char ch;
X{
X	int i = char2int(ch);			/* 8 bits only */
X	
X	return is_ascii95(i) ? i : '?';
X}
X
Xexpose()	{
X	if (size == 0)
X		printf("\t* * * TAPE MARK * * *\n");
X	else	{
X		int i;
X		printf("\t");
X		for (i = 0; i < WIDTH && i < size; i++)	{
X			printf("%c", printable(buff[i]));
X		}
X		printf("\n  EBC:\t");
X		for (i = 0; i < WIDTH && i < size; i++)	{
X			printf("%c", printable(ebc2asc(buff[i])));
X		}
X		printf("\n  HEX:\t");
X		for (i = 0; i < WIDTH/2 && i < size; i++)	{
X			char ch = buff[i];
X			printf("%c%c", hex(ch>>4), hex(ch));
X		}
X		printf("\n");
X	}
X}
X
+ END-OF-FILE survey.c
chmod 'u=rw,g=r,o=r' \s\u\r\v\e\y\.\c
set `sum \s\u\r\v\e\y\.\c`
sum=$1
case $sum in
22800)	:;;
*)	echo 'Bad sum in '\s\u\r\v\e\y\.\c >&2
esac
echo Extracting \N\O\S\s\p\l\i\t\.\c
sed 's/^X//' > \N\O\S\s\p\l\i\t\.\c << '+ END-OF-FILE '\N\O\S\s\p\l\i\t\.\c
X/*	This file is part of the magtape handling package MAG.
X	Written by Dick Grune, Vrije Universiteit, Amsterdam.
X*/
X
X/*
X * Name: NOSsplit, split Cyber system tape (data format is SI)
X * Version: 820314
X */
X
X#define	MSGUSE	"Usage is: NOSsplit [-cfhlm[s N]] [out_name]\n"
X
X#include	<stdio.h>
X#include	"aux.h"
X#include	"tp.h"
Xextern char *sprintf();
X
X#define	MINSIZE	6			/* smaller is a noise block */
X#define	BSIZE	3840			/* blocksize binary files */
X#define	CSIZE	960			/* blocksize coded files */
X#define	SIZE	3840			/* maximum blocksize */
X#define	EORM	"\055\023\035\052\027\054\000"
X#define	EORL	7
X#define	EOS	'\0'
X
X#define	lastblock(n)	((n)!=BSIZE && (n)!=CSIZE)
X#define	cybln(n)	((n)*8/60*10)
X
Xint fnumber = 0;
Xchar *ofil = "x";
Xchar fname[128];
XFILE *outf;
X
Xchar buff[SIZE];
Xint size;	/* number of chars in `buff' */
Xint bpos;	/* number of bits consumed by `get6bits' */
Xint bstat;
X
Xint unit = 0;
Xint skipf = 0;		/* number of logical records to skip (forwards) */
Xchar *nmdns = TP_DENN;
XTPFILE *tf;
X
Xchar *progname;
X
Xmain(argc, argv)
X	char *argv[];
X{
X	progname = argv[0];
X	argc--, argv++;
X
X	while (argc > 0 && argv[0][0] == '-')	{
X		char *pp = argv[0];
X		
X		while (*++pp)	{
X			switch (*pp)	{
X			/* insert cases to handle the standard options */
X#include	"options.h"
X			/* special options */
X			case 's':
X				if (argc < 2)
X					goto Lbad;
X				if (!is_digit(argv[1][0]))
X					goto Lbad;
X				skipf = atoi(argv[1]);
X				argc--, argv++;
X				break;
X			}
X		}
X		argc--, argv++;
X	}
X
X	if (argc == 1)	{
X		ofil = argv[0];
X		argc--, argv++;
X	}
X
X	if (argc != 0)
X		goto Lbad;
X
X	read_tape();
X	exit(0);
X
XLbad:
X	fprintf(stderr, MSGUSE);
X	exit(1);
X
X}
X
Xread_tape()	{
X	int i;
X	int bcnt;
X
X	tperrout(stdout);
X	tf = tpopen(unit, nmdns, "rx");
X
X	fillbuff();
X	if (size == 80 && strncmp(buff, "VOL1", 4) == 0)	{
X		printf("This is a labelled tape\n");
X		printf("For label information use `ansir -pn'\n");
X		while (size > 0)
X			fillbuff();
X		if (size == 0)
X			fillbuff();
X	}
X	else	printf("This is a non-labelled tape\n");
X
X	for (i = 0; i < skipf; i++)	{
X		if (size <= 0)	{
X			printf("%d record%s missing\n", english(skipf-i));
X			exit(1);
X		}
X		fnumber++;
X		while (!lastblock(size))
X			fillbuff();
X		fillbuff();
X	}
X
X	if (skipf > 0)
X		printf("%d logical record%s skipped\n", english(skipf));
X
X	while (size > 0)	{
X		newcreat(fnumber++);
X
X		bcnt = 1;
X		while (putbuff(cybln(size)), !lastblock(size))	{
X			fillbuff();
X			bcnt++;
X		}
X
X		proc_eor(bcnt);
X
X		VOID(fclose(outf));
X		outf = NULL;
X		fillbuff();
X	}
X
X	printf("%d record%s retrieved\n", english(fnumber-skipf));
X}
X
Xnewcreat(fn)	{
X	int i;
X
X	for (i=0; ofil[i] != EOS; i++)
X		fname[i] = ofil[i];
X	VOID(sprintf(&fname[i], "%04d", fn));
X	outf = fopen(fname, "w");
X	if (outf == NULL)	{
X		printf("%s: cannot create `%s'\n", progname, fname);
X		exit(1);
X	}
X}
X
Xfillbuff()	{
X
X	do	size = tpread(tf, buff, sizeof buff);
X	while (size > 0 && size < MINSIZE /* noise record */);
X	bpos = bstat = 0;
X}
X
Xputbuff(n)
X	int n;				/* number of 6bit chars */
X{
X
X	while (n-- > 0)
X		putc(get6bits(), outf);
X}
X
X
Xproc_eor(bcnt)	{
X	char eor[EORL];
X	int i;
X
X	for (i = 0; i < EORL; i++)
X		eor[i] = get6bits();
X
X	printf("%s: ", fname);
X	printf("%d block%s, ", english(bcnt));
X	if (strncmp(eor, EORM, EORL) != 0)
X		printf("no proper EOR\n");
X	else
X		printf("EOR%2o\n", get6bits());
X}
X
X#define	left(c,n)	(((c)&((077<<(8-(n)))&0377))>>(8-(n)))
X#define	right(c,n)	(((c)&((077>>(6-(n)))&0377))<<(6-(n)))
X/*
X * These forms are constructed through program transformations; the
X * author cannot, by any stretch of imagination, guess why they work.
X */
X
Xint
Xget6bits()	{
X	int res = 0;
X
X	switch (bstat++)	{
X	case 0:	res = left(buff[bpos+0], 6);
X		break;
X	case 1:	res = right(buff[bpos+0], 2) + left(buff[bpos+1], 4);
X		break;
X	case 2:	res = right(buff[bpos+1], 4) + left(buff[bpos+2], 2);
X		break;
X	case 3:	res = right(buff[bpos+2], 6);
X		break;
X	}
X	if (bstat == 4)	{
X		bpos += 3;
X		bstat = 0;
X	}
X	return res;
X}
+ END-OF-FILE NOSsplit.c
chmod 'u=rw,g=r,o=r' \N\O\S\s\p\l\i\t\.\c
set `sum \N\O\S\s\p\l\i\t\.\c`
sum=$1
case $sum in
08337)	:;;
*)	echo 'Bad sum in '\N\O\S\s\p\l\i\t\.\c >&2
esac
echo Extracting \N\O\S\t\r\.\c
sed 's/^X//' > \N\O\S\t\r\.\c << '+ END-OF-FILE '\N\O\S\t\r\.\c
X/*	This file is part of the magtape handling package MAG.
X	Written by Dick Grune, Vrije Universiteit, Amsterdam.
X*/
X
X/*
X * Program: NOStr, translates a Cyber 6-bit file into a UNIX ASCII file.
X * Version: 820314
X */
X
X#define	MSGUSE	"Usage is: NOStr -C [file]"
X
X#include	<stdio.h>
X#include	"aux.h"
X
X#define	MAXERR	40
X#define	EOS	'\0'
X
XFILE	*ifile;		/* input file */
Xchar	*iname;		/* input name */
X
Xint displZ(), asciiZ(), binary();
Xstruct conv	{
X	char *name;
X	int (*command)();
X	char *expl;
X} conv[] =	{
X	{"d", displZ, "Z-type records in DISPLAY code"},
X	{"a", asciiZ, "Z-type records in ASCII95"},
X	{"b", binary, "binary, = ASCII256"}
X};
X
Xmain(argc, argv)
X	char *argv[];
X{
X	int p;
X
X	if (argc < 2 || argc > 3 || argv[1][0] != '-' || strlen(argv[1]) != 2)
X		goto Bad_usage;
X	if (argc == 2 || strcmp(argv[2], "-") == 0)	{
X		iname = "standard input";
X		ifile = stdin;
X	}
X	else	{
X		iname = argv[2];
X		ifile = fopen(iname, "r");
X		if (ifile == NULL)	{
X			fprintf(stderr, "%s: cannot open %s\n",
X					argv[0], iname);
X			exit(1);
X		}
X	}
X	for (p = 0; p < n_items(conv); p++)
X		if (strcmp(&argv[1][1], conv[p].name) == 0)	{
X			(*conv[p].command)();
X			exit(0);
X		}
XBad_usage:
X	fprintf(stderr, MSGUSE);
X	fprintf(stderr,
X		"\nwhere the conversion code C is one of the following:\n");
X	for (p = 0; p < n_items(conv); p++)
X		fprintf(stderr, "`%s': %s\n", conv[p].name, conv[p].expl);
X	exit(1);
X}
X
X#define	NL	'\n'
X#define	TEN	10
X
Xint cwrd[TEN];
Xlong lcnt = 1;
Xlong icnt = 0;
X
XdisplZ()	{	/* recognize Z-type records in DISPLAY code */
X	int nch;
X	int zpend = 0;
X
X	while (nch = get_cwrd(TEN), nch != 0)	{
X		int i;
X
X		if (nch != TEN)
X			VOID(complain("short word", 0));
X		while (nch != 0 && cwrd[nch-1] == 0)
X			nch--;
X		if (zpend && nch > 0)
X			putdispl(0);	/* zero pending */
X		for (i = 0; i < nch; i++)
X			putdispl(cwrd[i]);
X		if (nch < TEN-1)
X			putascii(NL);
X		zpend = nch == TEN-1;
X	}
X}
X
X#define	FIVE	5
X
XasciiZ()	{	/* recognize Z-type records in ASCII95 */
X	int nch;
X
X	while (nch = get_cwrd(FIVE), nch != 0)	{
X		int i;
X
X		if (nch != FIVE)
X			VOID(complain("short word", 0));
X		while (nch != 0 && cwrd[nch-1] == 0)
X			nch--;
X		for (i = 0; i < nch; i++)
X			putascii(cwrd[i]);
X		if (nch < FIVE)
X			putascii(NL);
X	}
X}
X
Xbinary()	{	/* binary, also ASCII256 */
X	int ch;
X
X	while (ch = get12bits(), ch != EOF)
X		putascii(ch);
X}
X
Xint
Xget_cwrd(n)	{	/* gather n (60/n)-bit bytes into a Cyber word */
X	int i;
X
X	for (i = 0; i < n; i++)	{
X		cwrd[i] = n == TEN ? get6bits() :
X				n == FIVE ? get12bits() : (abort(), 0);
X		if (cwrd[i] == EOF)
X			break;
X	}
X	return i;
X}
X
Xint
Xget12bits()	{
X	int ch1, ch2;
X	static errcnt = 0;
X
X	ch1 = get6bits();
X	if (ch1 == EOF)
X		return EOF;
X	ch2 = get6bits();
X	if (ch2 == EOF)
X		ch2 = 0;
X
X	ch1 = (ch1 << 6) + ch2;
X	if (ch1 >> 8)
X		errcnt = complain("composed char wider than 8 bits", errcnt);
X	return ch1;
X}
X
Xint
Xget6bits()	{
X	int ch = getc(ifile);
X	static errcnt = 0;
X
X	if (ch == EOF)
X		return EOF;
X	icnt++;
X	if (ch >> 6)
X		errcnt = complain("input char wider than 6 bits", errcnt);
X	return ch;
X}
X
Xputdispl(ch)	{	/* convert display to ASCII */
X	putchar(
X	"%ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+-*/()$= ,.#[]:\"_!&'?<>@\\^;"
X		[ch]);
X}
X
Xputascii(ch)
X	char ch;
X{
X	putchar(ch);
X	if (ch == NL)
X		lcnt++;
X}
X
Xint
Xcomplain(s, n)
X	char *s;
X{
X	if (n > MAXERR)
X		return n;
X	fprintf(stderr,
X		"At input char %ld, at output line %ld, %s in file `%s'\n",
X				icnt, lcnt, s, iname);
X	if (n == MAXERR)
X		fprintf(stderr,
X	"After %d complaints, further complaints of this type suppressed\n",
X			MAXERR);
X	return n+1;
X}
+ END-OF-FILE NOStr.c
chmod 'u=rw,g=r,o=r' \N\O\S\t\r\.\c
set `sum \N\O\S\t\r\.\c`
sum=$1
case $sum in
55112)	:;;
*)	echo 'Bad sum in '\N\O\S\t\r\.\c >&2
esac
exit 0

-- 

Rich $alz			"Anger is an energy"
Cronus Project, BBN Labs	rsalz@bbn.com
Moderator, comp.sources.unix	sources@uunet.uu.net