/* mytar.c - just read tar tapes for now */
#include <stdio.h>
#include <cx.h>
#include <qiofun.h>
#include <qioret.h>
#include <algol68.h>
#define EFN 1
#define LUN 6
#define BUFSIZ 16384
extern int $$ferr;

struct	header
BEGIN
	char	name[100];
	char	mode[8];
	char	uid[8];
	char	gid[8];
	char	size[12];
	char	mtime[12];
	char	chksum[8];
	char	linkflag;
	char	linkname[100];
END;

char	buffer[BUFSIZ];	/* magtape record */
char	*bufptr;	/* where in buffer to get next 512-byte block */
long	blk512;		/* ordinal of block recently read into block */
int	leftinbuf;	/* number of bytes left in buffer */
			/* excludes BLKSIZ bytes @ bufptr */
#define BLKSIZ 512	/* number of bytes in a tar block */
#define NUMDIR 30	/* number of directory levels expected		*/
char dir[100][NUMDIR];	/* directory names of last file			*/
int dirchr[NUMDIR];	/* how we encode each directory name into chars */
char *where[NUMDIR];	/* where each directory name begins in names	*/
char names[100];	/* the file name, broken up into directory names*/
char	**w;		/* tracks where[]				*/
char	*d;		/* tracks dir[][]				*/
int	j;		/*						*/
int	number;		/*						*/
int	letter;		/*						*/
char	app[4];		/* code for this directory name			*/
char temp[100];		/*						*/

main()
BEGIN
int	i;
char	rsxnam[42];
FILE * rsxfil;		/* used to write disk files			*/
int	dsw;
long	thesize;	/* number of blocks left in this file		*/
int	filnum;		/* file number on tape				*/
struct header *hdrptr;
int	csum;		/* the tape's checksum				*/
int	mycsum;		/* my checksum					*/
char	*p;		/*						*/
char	*en;		/* end of a buffer segment			*/
int	blox;		/* number of unix blocks in this file		*/
int	dicsum;		/* difference in checksums			*/

	dsw = alun(LUN,'MT',0);	/* assume mt0: is device */
	IF	(dsw!=IS_SUC)
	THEN	error("alun dsw=%oo\7",dsw);
	FI;
	blk512 = -1;
	leftinbuf = 0;	/* kickstart nxtblk()				*/

	FOR	(i=0;	i<NUMDIR;	i++)
	DO	dirchr[i] = 0;
	OD;
	dir[0][0] = 42;	/* impossible node name				*/

	FOR	(filnum=0;	nxtblk();	filnum++)
				/* hope another directory block		*/
	DO	hdrptr = (struct header *) bufptr;
		sscanf(hdrptr->size,"%lo",&thesize);
		sscanf(hdrptr->chksum,"%o",&csum);
		mycsum = 0;
		en = (char *) hdrptr->chksum;
		FOR	(p=(char*)hdrptr;	p<en;	p++)
		DO	mycsum += (int)*p;
		OD;
		en = &hdrptr->linkname[100];
		FOR	(p=(char*)&hdrptr->linkflag;	p<en;	p++)
		DO	mycsum += (int)*p;
		OD;
		mycsum += 8*' ';
		dicsum = mycsum - csum;
		IF	(dicsum)
		THEN	printf("mycsum=%d. csum=%d. dif=%d.\n",mycsum,csum,dicsum);
			en = (char *) hdrptr + BLKSIZ;
			FOR	(i=1,p = (char*) hdrptr;	p<en;	p++,i++)
			DO	printf("%02x",*p);
				IF	(!(i&0xF))
				THEN	putchar('\n');
				FI
			OD;
			error("aborted due to bad checksum: blk512=%loo\n");
		FI;
		IF	(hdrptr->linkflag=='1')
		THEN	blox = 0;	/* no actual data in linked file */
		ELSE	blox = (int) ((thesize+(long)(BLKSIZ-1))/BLKSIZ);
		FI;
		strcpy(rsxnam,"ta:");
		strcpy(names,hdrptr->name);
		FOR	(i=0,where[0]=p=names;	*p;	p++)
		DO	IF	(*p=='/')
			THEN	*p=0;
				where[++i]=p+1;
			FI;
		OD;
		where[++i] = 0;
		FOR	(w=where,i=0;	*w;	w++,i++)
		DO	/* i indexs dir[i][] */
			d = dir[i];
			IF	(!streq(d,*w))
			THEN	dirchr[i]++;
				strcpy(dir[i],where[i]);
				FOR	(j=i+1;	where[j];	j++)
				DO	dirchr[j] = 0;
					strcpy(dir[j],where[j]);
				OD;
				FOR	(;	j<NUMDIR;	j++)
				DO	dir[j][0]=0;
					dirchr[j]=0;
				OD;
			FI;
			number = dirchr[i] / 26;
			letter = dirchr[i] % 26;
			IF	(number)
			THEN	app[0] = '0'-1+number;
				app[1] = letter+'a';
				app[2] = 0;
			ELSE	app[0] = letter+'a';
				app[1] = 0;
			FI;
			strcat(rsxnam,app);
		OD;
		IF	(strlen(rsxnam)>9)
		THEN	strcpy(temp,rsxnam+9);
			strcpy(rsxnam+9,".");
			strcat(rsxnam,temp);
		FI;
		IF	( ! (rsxfil=fopen(rsxnam,"w")))
		THEN	error("$$ferr=%oo rsxnam=%s\tblk512=%loo\7",$$ferr,rsxnam,blk512);
		FI;
		printf("%12lo %18s\t%12ld %s\n",blk512,rsxnam,thesize,hdrptr->name);
		WHILE	(blox--)
		DO	IF	(!nxtblk())
			THEN	error("unexpected end: blox=%d. blk512=%loo\7",blox,blk512);
			ELSE	en = bufptr+(blox?BLKSIZ:(int)(thesize%(long)BLKSIZ));
				FOR	(p=bufptr;	p<en;	p++)
				DO	putc(*p,rsxfil);
				OD;
			FI;
		OD;
		fclose(rsxfil);
	OD;
END

int	nxtblk()	/* return FALSE if tape eof / error */
			/* bufptr = address of next BLKSIZ block of data */
BEGIN
int	myisb[2];
int	mydsw;
	IF	(!leftinbuf)
	THEN	leftinbuf = rmtrec(LUN,BUFSIZ,buffer,EFN,myisb,&mydsw);
		bufptr = buffer - BLKSIZ;
	FI;
	IF	(leftinbuf <=0)
	THEN	IF	(!leftinbuf)
		THEN	fprintf(stderr,"isb=%oo%oo dsw=%oo\7\n",myisb[0],myisb[1],mydsw);
			return(FALSE);
		ELSE	error("leftinbuf=%d. blk512=%ld.\7",leftinbuf,blk512);
		FI;
	ELSE	leftinbuf -= BLKSIZ;
		bufptr += BLKSIZ;
		blk512 ++;
		return(TRUE);
	FI;
END

int 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
	{fprintf(stderr,"ids=%oo isb=%oo%oo",ids,isb[0],isb[1]);
	 got=0;	/* some error */
	}
 ;
 return (got);
}
/* end: mytar.c */
