/* t2b.c: read a R.VAR file from tape */
/* format of output file is 1 record :: 1 tape block */
/* a 0-length output record means a tape-mark was read */
/* now with featuritus: you can get R.FIX files output! */
#include <stdio.h>
#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		ascii[256];	/* ebcdic->ascii table */
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<>"" */
unsigned	recspat;	/* incremented each record output this file */
int		fixlen;		/* TRUE if not R.VAR output */
helpless()
{puts("usage: T2B MTn [first-record-ordinal] [last-record-ordinal] [-e] [maxoutrecsiz] [outfile] [quantum] [-f]");
 puts("copies MTn: to stdout or nominated file(s)");
 puts("each record of stdout maps to one tape record");
 puts("a tape mark is written as an empty output record");
 puts("reading stops at EOT");
 puts("each record read is numbered, starting at zero");
 puts("a tape mark counts as one record");
 puts("first-record-ordinal defaults to zero");
 puts("last-record-read defaults to a VERY large number");
 puts("if the record read has a number outside f-r-o to l-r-o inclusive");
 puts(" then that record is NOT output: tape reading stops after the l-r-o record");
 puts("record ordinals should be typed in as unsigned decimal integers");
 puts("a 4th command argument of \"-e\" means convert each byte from EBCDIC to ASCII");
 puts("a 4th argument of \"-a\" means leave bytes alone - they are in ASCII already");
 puts("a 5th argument is a decimal number: the maximum output record size");
 puts("if the 5th argument is used, long output records are fractured into parts");
 puts("all but the last part of a record will be <arg5> bytes long");
 puts("using arg5>0 means that B2T will not restore the tape correctly!");
 puts("a 6th argument is a filename. If present, many files are output.");
 puts("Each time a file-mark is seen, a new file is started.");
 puts("also, no empty record is output like normal.");
 puts("Each file has a name {filename}n where n is counted from 1.");
 puts("use \"\" as a place-holder for 6th argument.");
 puts("a 7th argument is a decimal number: each 'quantum' records a tapemark is faked.");
 puts("an absent or zero 7th argument means don't fake file marks.");
 puts("for example quantum of 1000 means fake tapemark after each 1000. records.");
 puts("a 8th argument of \"-f\" means LOOSE the record lengths from");
 puts("the front of each record: means B2T can't use the output file");
 puts("this is mainly used for dense image copies of tapes");
 exit();
}
main(argc,argv)
char **argv;
{unsigned	u;
 char		c;
 int		i;
 char		*p;
 int		toupper();
 int		ids;		/* directive status word */
 int		isb[2];		/* qio status block */
 unsigned	got;
 char		dnam[3];	/* magtape device name (ASCII) */
 int		dnum;		/* magtape unit number */
 int		dev;		/* word-aligned device name */
 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 */
#include "cascii.h"
/* above is a gross patch until I figure out how to initialise arrays in C */
 if	(argc==0)
	{helpless();
	}
 ;
 if	(strlen(argv[1])!=3 || !isdigit(argv[1][2]))
	{puts("\7First Argument must be EXACTLY ddn");
	 helpless();
	}
 ;
 copy(dnam,argv[1],2);
 dnum=argv[1][2]-'0';
 dev = toupper(dnam[1])<<8 | toupper(dnam[0]);
 dsw=alun(LUN,dev,dnum);
 if	(dsw!=IS_SUC)
	{error("\7Can't attach to %s dsw=%o",argv[1],dsw&0xFF);
	}
 ;
 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 */
 if	(argc>2)
	{sscanf(argv[2],"%ld",&fro);
	 if	(argc>3)
		{sscanf(argv[3],"%ld",&lro);
		 if	(argc>4)
			{c=toupper(argv[4][1]);
			 if	(argv[4][0]!='-'
				||strlen(argv[4])!=2
				||c!='A'&&c!='E'
				)
				{puts("\74th argument may only be \"-e\" or \"-a\"!");
				 helpless();
				}
			 ;
			 e2a = c=='E';
			 if	(argc>5)
				{sscanf(argv[5],"%d",&morz);
				 if	(morz<0)
					{puts("\7negative maximum output record size");
					 helpless();
					}
				 ;
				 if	(argc>6)
					{strcpy(outfile,argv[6]);
					 filenum=0;
					 if	(argc>7)
						{sscanf(argv[7],"%d",&quantum);
						 if	(argc>8)
							{fixlen = (argv[8][0]=='-') && (tolower(argv[8][1])=='f');
							}
						 ;
						}
					 else
						{quantum=0;
						}
					 ;
					}
				 else
					{strcpy(outfile,"");
					 quantum=0;
					}
				 ;
				}
			 ;
			}
		 ;
		}
	 ;
	}
 ;
 if	(fixlen)
	{ioptr=fopen(outfile,"wn");
	 recspat = 0;
	}
 else
	{if	(*outfile)
		{nextfile();
		}
	 else
		{ioptr=stdout;
		 recspat=0;
		}
	 ;
 }
 eof1=FALSE;
 ro=0;
 while	((got=rmtrec(LUN,BUFSIZ,b,EFN,isb,&ids)) || isb[0]==IE_EOF )
	{
/*	 printf("got=%d.\n",got);
	 for	(u=0;	u<got;	u++)
		{printf("%02x  ",b[u]&0xFF);
		}
	 ;
	 putchar('\n');
*/
	 if	(isb[0]==IE_EOF)
		{if	(fro <= ro && ro <= lro)
			{/* null record :: tape mark */
			 if	(*outfile)
				{last();
				 nextfile();
				}
			 else
				{spew(b,0,ioptr);
				}
			 ;
			}
		 ;
		 if	(eof1)
			{quit();
			}
		 else
			{eof1=TRUE;
			}
		 ;
		}
	 else
		{if	(fro <= ro && ro <= lro)
			{if	(e2a)
				{for	(u=0; u<got; u++)
					{i=b[u] & 0xFF;	/* loose sign extend */
					 b[u]=ascii[i];
					}
				 ;
				}
			 ;
			 if	(morz)
				{p=b;
				 i=0;
				 while	(i<got)
					{u=got-i;
					 if	(u>morz)	u=morz;
					 spew(p,u,ioptr);
					 p+=u;
					 i+=u;
					}
				 ;
				}
			 else
				{spew(b,got,ioptr);
				}
			 ;
			}
		 ;
		 eof1=FALSE;
		}
	 ;
	 ro++;	/* advance record counter */
	 if	(ro > lro)
		{quit();
		}
	 ;
	}
 error("\7Can't read record isb[0]=%oo isb[1]=%oo ids=%oo\n",isb[0],isb[1],ids);
}
last()
{
 fflush(ioptr);
 if	(fclose(ioptr))	error("\7Can't close %s $$ferr=%oo\n",filename,$$ferr);
}
nextfile()
{
 filenum++;
 sprintf(filename,"%s%d",outfile,filenum);
 if	(!(ioptr=fopen(filename,"w")))	error("\7Can't open %s $$ferr=%oo\n",$$ferr);
 recspat=0;
}
quit()
{last();
 exit();
}
spew(buf,len,ptr)
char		*buf;	/* source of record */
unsigned	len;	/* length of record */
FILE		*ptr;	/* destination of record */
{
 if	(fixlen)
	{recsiz(ptr,len);
	}
 ;
 fput(buf,len,ptr);
 if	(ferror(ptr))	error("\7len=%d. $$ferr=%oo\n",len,$$ferr);
 recspat++;
 if	(quantum && recspat>=quantum)
	{last();
	 nextfile();
	}
 ;
}
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 */
{
 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)
	{got=isb[1];
	}
 else
	{got=0;	/* some error */
	}
 ;
 return (got);
}
