
/*
 * print a PDP9/15 DECtape directory
 *
 * directory data  at offset 040 in block 0100
 * 56 entries (or 24 if system tape, with other half of blk for sys files)
 *
 * name           (in line printer format)
 * name
 * extension
 * starting block (msb set if file active)
 *
 */

#include <stdio.h>

FILE *fp, *fp1;

char fileName[15] = { 0,0,0,0,0,0,'_',0,0,0,'.','t','x','t',0};

unsigned int tape[576][256];

unsigned int blk[256];

#define FWD 0
#define REV 1

unsigned int direction = FWD;

getblk(blknum)
{
	unsigned int i, j;
	unsigned int wrd;
	unsigned int *p,*q;

	if(blknum > 01077){
		fprintf(stderr,"error - blknum too big in getblk %o\n", blknum);
		exit(1);
	}
//	if(direction == FWD){
	if(((tape[blknum][255] & 0770000) == 0) ||            // normal blknum
	    (tape[blknum][255] == 0777777)){                  // or EOF
	 // fprintf(stderr,"\n---BLK %o FWD, link %o\n", blknum, tape[blknum][255]);
	 p = blk;
	 for(i=0; i<256; i++) *p++ = tape[blknum][i];
	}
	else{                          // blks read REV req obverse compliment
	 // fprintf(stderr,"\n---BLK %o REV, link %o\n", blknum, tape[blknum][255]);
	 p = blk;
	 q = &tape[blknum][255];
	 while(p != &blk[256]){
		 wrd  = ~(*q--);
	         j  = (wrd & 0700000) >>15;
		 j |= (wrd & 0070000) >> 9;
		 j |= (wrd & 0007000) >> 3;
		 j |= (wrd & 0000700) << 3;
		 j |= (wrd & 0000070) << 9;
		 j |= (wrd & 0000007) <<15;
	         *p++ = j; 
	 }
	}
}

//
// 6-bit trimmed code
// 0xAB is <left arrrow> on a mac
//
unsigned char tbl[64] = { '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
                          'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
                          'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
                          'X', 'Y', 'Z', '[', '\\', ']', '^', 0xab,
                          ' ', '!', '"', '#', '$', '%', '&', '\'',
                          '(', ')', '*', '+', ',', '-', '.', '/',
                          '0', '1', '2', '3', '4', '5', '6', '7',
                          '8', '9', ':', ';', '<', '=', '>', '?'};

sixbit(fp, i)
FILE *fp;
unsigned int i;
{
	unsigned int chr;
	chr = (i >> 12) & 077;
	if(chr == 0) chr = 040;  // change nuls to spaces for file names
        fprintf(fp, "%c",tbl[chr]);
        chr = (i >> 6)  & 077;
	if(chr == 0) chr = 040;
        fprintf(fp, "%c",tbl[chr]);
        chr = i & 077;
	if(chr == 0) chr = 040;
        fprintf(fp, "%c",tbl[chr]);
}

sixbitstr(p, i)
char *p; unsigned int i;
{
	unsigned char chr;
	*p++ = tbl[(i >> 12) & 077];
	*p++ = tbl[(i >> 6)  & 077];
	*p++ = tbl[ i        & 077];
}

int nulDetected = 0;
unsigned char lastChr = 0;

fiveSevenOut(fp,i,j)
FILE *fp;
unsigned int i,j;
{
	unsigned char c[5];
	unsigned char chr;
	int cnt;

	if(nulDetected) return;

	c[0] = (i>>11) &0x7f;
        c[1] = (i>>4)  &0x7f;
	c[2] = ((i<<3) &0170) | ((j>>15) & 07);
	c[3] = (j>>8)  &0x7f;
	c[4] = (j>>1)  &0x7f;
	/*
	 * this is all complicated by the fact that there can be
	 * extra words after the end of line, and nuls before the
	 * first <cr>
	 *
	 * this code assumes there is only ever a single line ending
	 * in <cr> or <cr><lf> per record
	 */
	for(cnt=0; cnt<5; cnt++){
	 chr = c[cnt];
	 if((chr == 0xd)||(chr == 0)){
		 fputc('\n',fp );
		 nulDetected++;
		 return;
	 }
	 else 
		 fputc(chr, fp);
	}
}

main(argc, argv)
int argc;
char **argv;
{
	unsigned int *p, *dirPtr;
	unsigned int i, j, n, wrd, n1,n2,n3;
	unsigned int curblk, blkcnt, dirSlot;
	unsigned int cnt;
	int textFile = 0;

	// read and unpack the entire tape
	for(i=0; i<576; i++){
	 for(n=0; n<256; n++){
		 wrd =  getchar();
		 wrd |= getchar() << 8;
		 wrd |= (getchar() & 3) << 16;
		 getchar();
		 tape[i][n] = wrd;
	 }
	}

	dirPtr = &tape[0100][040]; 				// addr of start of directory

	fp1 = fopen("_directory.txt","w");

	for(dirSlot=0; dirSlot<56; dirSlot++){

	 //printf("\n----DIRSLOT %d ", dirSlot);

	 n1 = *dirPtr++; n2 = *dirPtr++; n3 = *dirPtr++;	// file name
	 n = *dirPtr++;

	 //printf(" FIRST BLK %o\n", n); fflush(stdout);

	 if((n & 0400000) == 0) continue;
	 n &= 01777;
	 if(n > 01077) continue;			// 576 (01100) octal blocks on tape
	 if(n == 0) { printf("\n"); continue; }		// system file
	 sixbit(fp1, n1);
	 sixbit(fp1, n2);
	 fprintf(fp1, " ");
	 sixbit(fp1, n3);
	 fprintf(fp1, " %4o ", n);
	 blkcnt = 0;
	 curblk = n;
	 getblk(curblk);
	 fprintf(fp1," %s  ",(blk[0] & 7) == 2 ? "TXT": "BIN");			
//
// extract code
//

	 if((blk[0] & 7) != 2) 
		 textFile = 0;
	 else
		 textFile = 1; 		// only extract text files

	 sixbitstr(fileName, n1);
	 sixbitstr(&fileName[3], n2);
	 sixbitstr(&fileName[7], n3);
	 for(i=0; i<10; i++){
		if(fileName[i] == '@') fileName[i] = '_';
	 }

	 if(textFile)
		 fp = fopen(fileName,"w");

	 while(1){
	 	blkcnt++;
	 	//printf("\nCnt: %d Link: %6o %6o\n",blkcnt, blk[254],blk[255]);
		//printf("curblk = %o next = %o\n", curblk, blk[255]); fflush(stdout);

		if(textFile)
	 	for(j=0; j<254; ){
		 	if(blk[j] == 001005){
				//printf("hit sw EOF");
				break;
			}
			if(blk[j] == 0)
				break;
		 	// extract record length
		 	cnt = ((blk[j] >> 9) & 0xff);
		 	//printf("\n --typ %d cnt %d : ",blk[j] & 7,cnt); fflush(stdout);
			nulDetected = 0;
			j += 2;
			// extract data
			//
		 	while(--cnt){
			 //printf("\n%6o %6o ",blk[j], blk[j+1]);
		 	 //fiveSevenOut(stdout, blk[j], blk[j+1]);
			 fiveSevenOut(fp, blk[j], blk[j+1]);
			 j += 2;
		 	}
	 	}

		//if(curblk > blk[255]) direction = REV; else direction = FWD;
		if(blk[255] == 0777777) break; // last blk in file
	 	curblk = blk[255];
		getblk(curblk);
	 }

	 if(textFile) 
		 fclose(fp);

	 fprintf(fp1,"%d\n",blkcnt);
	}

	fclose(fp1);
}
