/* i.c - a prototype for an RMS-11 untangler */
/* this one is for rooted root blocks - given a data block, follow
 * the chain until we find gangrene
 */

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

#include <cx.h>
#include <nboff.h>
#include <fdoff.h>
FDB *	fdbp;

BOOL	gangrene;

FILE *	outptr;
long	recn;

int	nxtbyt;
int	nxtrid;
int	hirid;
long	nxtbkt;
int	bktlvl;
int	bktbcb;
struct rmsbkh* bkhp;
unsigned	bplen;
long	testvbn;
int	rrid;
int	flags;
unsigned	testrid;
BOOL	compressed;

char	answer[100];
long	vbn;
FILE *	ioptr;
char	buffer[512];
int	i;
char *	p;
char *	pend;

main()
BEGIN
	IF	(!(ioptr=fopenr("[43,43]bad",512)))
	THEN	error("can't open $$ferr=%oo",$$ferr);
	FI
	IF	(!(outptr=fopenc("datachain",0242)))
	THEN	error("can't create $$ferr=%oo",$$ferr);
	FI
	outptr -> _flag |= IO_NOS | _IONBF;
	fdbp = outptr -> io_fdb;
	fdbp -> f_fatt . f_ratt |= fd_cr;
	recn=1;
	printf("starting data block (decimal) :");
	gets(answer);
	sscanf(answer,"%ld",&vbn);
	FOR	(gangrene=FALSE; !gangrene; vbn=nxtbkt)
	DO
fprintf(stderr,"%ld.\n",vbn);
		IF	(frget(buffer,512,ioptr,vbn))
		THEN	fclose(outptr);
			error("read $$ferr=%oo\n",$$ferr);
		FI
#ifdef hexbyt
		FOR	(p=buffer,i=0; p<buffer+512; i++,p++)
		DO	IF	(!(i&0xF))
			THEN	putchar('\n');
			FI
			printf(" %02x",*p&0xFF);
		OD
#endif
		pain();
	OD
	fclose(outptr);
	fprintf(stderr,"%ld. records salvaged\n",recn-1);
END

pain()
BEGIN
	bkhp = buffer;
	IF	(bkhp->b_chk!=buffer[511])
	THEN	gringe("Check Byte Failed");
	ELSE	IF	(bkhp->b_taa)
		THEN	gringe("Not Area 0");
		ELSE	IF	(bkhp->b_adr!=(vbn&0xFFFF))
			THEN	gringe("Virtual Block Number Mismatch");
			ELSE	nxtbyt = bkhp->b_nby;
				IF	(nxtbyt>510)
				THEN	gringe("B$NBY assumed 510");
					nxtbyt = 510;
				FI
				nxtrid = bkhp->b_nid&0xFF;
				hirid = bkhp->b_lid&0xFF;
				IF	(hirid<nxtrid)
				THEN	winge("High RID < Next RID");
				FI
				nxtbkt = bkhp->b_nbk;
				longit(&nxtbkt);
				bktlvl = bkhp -> b_lev & 0xFF;
				bktbcb = bkhp -> b_bcb & 0xFF;
				FOR	(pend=buffer+nxtbyt,p=buffer+016; p<pend; )
				DO	bplen = *p & 0x3;
					flags = *p & 0xFC;
					compressed = flags & DC$NPS;
					IF	(bplen>2 && !compressed)
					THEN	gringe("LOST bad PS");
						break;
					ELSE	bplen += 2;
					FI
					p += 1;	/* step over control byte. p points to 2nd byte of header */
					IF	(bktlvl)
					THEN	gangrene = TRUE;
						/* how did we chain from a data bucket into an index bucket ? */
					FI
					IF	(bktlvl)
					THEN	/* index bucket */
						testvbn = 0L;
						copy(&testvbn,p,bplen);
						longit(&testvbn);
						p += bplen;
/*						printf("%7ld.\"%.21s\"\n",testvbn,p);
*/
						p += 025;	/*-----------------------------*/
					ELSE	testrid = *p & 0xFF;
						IF	(testrid>(bkhp->b_nid&0xFF))
						THEN	winge("excessive record ID");
						FI
						p += 1;
						IF	(compressed)
						THEN	/* deleted RRV - no further info */
						ELSE	rrid = *p & 0xFF;
							p += 1;
							copy(&testvbn,p,4);
							longit(&testvbn);
							p += 4;
							IF	(flags&DC$RRV)
							THEN	IF	(testvbn==vbn)
								THEN	winge("RRV points to self");
								FI
							ELSE	frput(p,0242,outptr,recn++);
								p += 0242;	/*--------------------------*/
							FI
						FI
					FI
				OD
				IF	(p!=pend)
				THEN	gringe("crud at bucket end");
				FI
			FI
		FI
	FI
END

winge(why)
char *	why;
BEGIN
	fprintf(stderr,"\7%7ld. %s\n",vbn,why);
	gangrene = TRUE;
END

gringe(why)
char *	why;
BEGIN
	fprintf(stderr,"\7%7ld. %s\n",vbn,why);
	gangrene = TRUE;
END

longit(intp)
int	intp[2];
BEGIN
register int temp;
	temp = intp[0];
	intp[0]=intp[1];
	intp[1]=temp;
END
