/* t3b.c - son of t2b.c - read a tape FAST for commercial media conversion */

char * documentation [] = {
"usage: T2B -fn -ln -e -mn -o -qn -x -zf f   ! all arguments are optional",
"copy MT0: to stdout, tape block -> disk record, tape mark -> empty record",
"quit @ end-of-tape",
"n== unsigned decimal long number    f== file name",
"-fn first record ordinal: don't write disk until this",
"-ln last record ordinal: exit after this (records start at # 0)",
"-e  convert each 8-bit byte from EBCDIC to ASCII",
"-mn maximum output record size (bytes) split longer records",
"    a disk record comes from at most one tape record",
"-o  repress output to stdout",
"-qn each n records a tapemark is faked (start new file after quantum)",
"-x  give R.FIX file, not R.VAR as normal",
"-zf make a file f, each line is the decimal length of a tape block read",
"f   this is a dotless file name. if present, many files are output",
"    being f.000 f.001 etc, each empty record (=tape mark) starts new file",
""
};

#include <algol68.h>
#include <stdio.h>

helpless(s)
char	*s;	/* why we give help to idiot */
BEGIN
	char	*p;
	char	**pp;

	fprintf(stderr,"T2B:\7error %s\n",s);
	FOR	(pp=documentation;	*(p=*pp);	pp++)
	DO	fprintf(stderr,"%s\n",p);
	OD;
	exit(1);
END

#include <cx.h>
#include <qiofun.h>
#include <qioret.h>
#define EFN 1
#define LUN 6
#define BUFSIZ 32769
extern int $$ferr;
char		b[BUFSIZ];
char		outfile[40];	/* output file name basis if any */
char		filename[50];	/* build output file name here */
unsigned	quantum;	/* non-zero: quantum to fake tapemark after */
unsigned	filenum;	/* last file number used when outfile<>"" */
FILE		*ioptr;		/* the output file when outfile<>"" */
				/* 0 means repress stdout (ie tape data) */
FILE		*fsiz;		/* write out each tape block size */
unsigned	recspat;	/* incremented each record output this file */
int		fixlen;		/* TRUE if not R.VAR output */
BOOL		output;		/* TRUE if user wants stdout */
#include "ascii.h"

main(argc,argv)
int	argc;
char	**argv;
BEGIN
	unsigned	u;
	char		c;
	int		i;
	char		*p;
	int		toupper();
	int		ids;		/* directive status word */
	int		isb[2];		/* qio status block */
	unsigned	got;
	int		dsw;		/* directive status word */
	int		eof1;		/* TRUE if just seen eof */
	unsigned	rmtrec();	/* read a magtape record (or tape mark) */
	int		morz;		/* maximum output record size */
	long int	fro;		/* first record ordinal */
	long int	lro;		/* last record ordinal */
	long int	ro;		/* current record ordinal */
	int		e2a;		/* TRUE if ebcdic to ascii conversion */
	dsw=alun(LUN,'MT',0);
	IF	(dsw!=IS_SUC)
	THEN	error("\7Can't attach to MT0: dsw=%o",dsw&0xFF);
	FI;
	fro=0;
	lro=1000000000L;
	e2a=FALSE;	/* assume no ebcdic to ascii conversion */
	morz=0;	/* assume no maximum output record size */
	fixlen = FALSE;/* assume no fixed-length output */
	strcpy(outfile,"");
	fsiz = NULL;
	quantum = 0;
	output = TRUE;	/* assume user wants output */
	FOR	(argc--,argv++;	argc;	argc--,argv++)
	DO	p = * argv;
		IF	(*p=='-')
		THEN	c = *++p;
			p++;	/* point after switch letter */
			switch	(tolower(c))
			BEGIN
			case 'e':	e2a = TRUE;
					break;
			case 'f':	sscanf(p,"%lu",&fro);
					break;
			case 'l':	sscanf(p,"%lu",&lro);
					break;
			case 'm':	sscanf(p,"%u",&morz);
					break;
			case 'o':	output = FALSE;
					break;
			case 'q':	sscanf(p,"%u",&quantum);
					break;
			case 'x':	fixlen = TRUE;
					break;
			case 'z':	fsiz = fopen(p,"w");
					/* NULL for fail is ok */
					IF	(!fsiz)
					THEN	fprintf(stderr,"WARNING\7 can't write record size file %s\n",p);
					FI;
					break;
			default:	fprintf(stderr,"bad switch %s\7\n",--p);
					helpless("don't understand command line");
					break;
			END
		ELSE	strcpy(outfile,p);
		FI
	OD
	IF	(output)
	THEN	IF	(fixlen)
		THEN	ioptr=fopen(outfile,"wn");
			recspat = 0;
		ELSE	IF	(*outfile)
			THEN	nextfile();
			ELSE	ioptr=stdout;
				recspat=0;
			FI
		FI
	ELSE	ioptr = 0;
	FI
	/* here with ioptr = 0 or an output channel */
	eof1=FALSE;
	ro=0;
	WHILE	((got=rmtrec(LUN,BUFSIZ,b,EFN,isb,&ids)) || isb[0]==IE_EOF )
	DO	IF	(fsiz)
		THEN	fprintf(fsiz,"%u\n",got);
		FI;
/*	 printf("got=%d.\n",got);
	 for	(u=0;	u<got;	u++)
		{printf("%02x  ",b[u]&0xFF);
		}
	 ;
	 putchar('\n');
*/
		IF	(isb[0]==IE_EOF)
		THEN	IF	(fro <= ro && ro <= lro)
			THEN	/* null record :: tape mark */
				IF	(*outfile)
				THEN	last();
					nextfile();
				ELSE	spew(b,0,ioptr);
				FI;
			FI;
			IF	(eof1)
			THEN	quit();
			ELSE	eof1=TRUE;
			FI;
		ELSE	IF	(fro <= ro && ro <= lro)
			THEN	IF	(e2a)
				THEN	FOR	(u=0; u<got; u++)
					DO	i=b[u] & 0xFF;	/* loose sign extend */
						b[u]=ascii[i];
					OD;
				FI;
				IF	(morz)
				THEN	p=b;
					i=0;
					WHILE	(i<got)
					DO	u=got-i;
						IF	(u>morz)
						THEN	u=morz;
						FI;
						spew(p,u,ioptr);
						p+=u;
						i+=u;
					OD;
				ELSE	spew(b,got,ioptr);
				FI;
			FI;
			eof1=FALSE;
		FI;
		ro++;	/* advance record counter */
		IF	(ro > lro)
		THEN	quit();
		FI;
	OD;
	error("\7Can't read record isb[0]=%oo isb[1]=%oo ids=%oo\n",isb[0],isb[1],ids);
END

last()
BEGIN
	IF	(ioptr)
	THEN	fflush(ioptr);
		IF	(fclose(ioptr))
		THEN	error("\7Can't close %s $$ferr=%oo\n",filename,$$ferr);
		FI
	FI
END

nextfile()
BEGIN
	filenum++;
	sprintf(filename,"%s.%03d",outfile,filenum);
	IF	(ioptr)
	THEN	IF	(!(ioptr=fopen(filename,"w")))
		THEN	error("\7Can't open %s $$ferr=%oo\n",$$ferr);
		FI
	FI
	recspat=0;
END

quit()
BEGIN
	last();
	IF	(fsiz)
	THEN	fclose(fsiz);
	FI;
	exit(0);
END

spew(buf,len,ptr)
char		*buf;	/* source of record */
unsigned	len;	/* length of record */
FILE		*ptr;	/* destination of record */
BEGIN
	IF	(ioptr)
	THEN	IF	(fixlen)
		THEN	recsiz(ptr,len);
		FI
		fput(buf,len,ptr);
		IF	(ferror(ptr))
		THEN	error("\7len=%d. $$ferr=%oo\n",len,$$ferr);
		FI
	FI
	recspat++;
	IF	(quantum && recspat>=quantum)
	THEN	last();
		nextfile();
	FI;
END

unsigned rmtrec(lun,bufsiz,buf,efn,isb,ids)	/* read a magtape record */
int	lun;		/* lun MT: lives on */
int	bufsiz;		/* buffer size for QIO */
char	*buf;		/* buffer to read data into */
int	efn;		/* event flag number to use */
int	isb[2];		/* i/o status block for qiow$ */
int	*ids;		/* directive status word returned */
BEGIN
	int	got;		/* return 0 or number of bytes read from record */
	int	prl[6];		/* parameter block for qiow$ */
	int	noast;		/*			 */
	int	qiow();
	noast=0;
	prl[0]=buf;
	prl[1]=bufsiz;
	*ids=qiow(IO_RLB,lun,efn,isb,noast,prl);
	IF	(isb[0]==IS_SUC)
	THEN	got=isb[1];
	ELSE	got=0;	/* some error */
	FI;
	return (got);
END

/* end: t3b.c */
