/* DECtape image scanner */

#include <stdio.h>
#define psym(k) fputc((k),stdout)
#define NL '\n'
#define CR '\r'
#define space() psym(' ')
#define newline() psym(NL)

static int *B;

void die (char *s, int n) {fprintf(stderr,"**SHIT(%o): %s\n",n,s); exit(1);}

int mangle (int n) {
int i,m;
  n = ~n;
  m = (n&7)<<15;
  m += (n&070)<<9;
  m += (n&0700)<<3;
  m += (n&07000)>>3;
  m += (n&070000)>>9;
  return m+((n&0700000)>>15);
}

void mangleblock (int block) {
int min,max,val;
  min = block*256; max = min+255;
/*fprintf(stderr,"Mangling block %o %o:%o %o %o,",*/
/*block,min,max,B[min],B[max]);*/
  while (min<max) {
    val = B[min]; B[min++]=mangle(B[max]); B[max--]=mangle(val);
  }
/*min=block*256;max=min+255;*/
/*fprintf(stderr," %o %o\n",B[min],B[max]);*/
}

void sixbt (int n) {
int i,j;
  for (i=12; i>=0; i-=6) {
    j = (n>>i)&63; if (j) {if ((j&32)==0) j+=64; psym(j);}
  }
}

void aa1 (int n) {
int i,j,k;
  for (i=12; i>=0; i-=6) {
    j = (n>>i)&63;
    if (j) {
      if ((j&32)==0) j+=64;
      if (j=='"') j = NL;
      if (j=='^') j = '@';
      psym(j);
    }
  }
}

void dec1 (int n) {
  n = n&127;
  if (n==CR) n = NL;
  if (n) psym(n);
}

void dec5 (int a, int b) {
  dec1(a>>11); dec1(a>>4);
  dec1((a<<3)+((b>>15)&7));
  dec1(b>>8); dec1(b>>1);
}

int bitmap (int fileno) {
  if (fileno<0) die("Fileno negative",fileno);
  if (fileno==0) return 256*64;
  if (fileno>56) die("Fileno excessive",fileno);
  return 256*57+((fileno-1)*32);
}

int blocksused (int bitmap) {
int i,j,m,n;
  n=0;
  for (i=0; i<32; i++) {
    m = B[bitmap++]; j = 0400000;
    while (j) {if (m&j) n++; j >>= 1;}
  }
  return n;
}

int filedesc (int fileno) {
  if (fileno<1) die("Fileno too small",fileno);
  if (fileno>56) die ("Fileno too big",fileno);
  return 256*64+(fileno-1)*4+32;
}

void printname (int d) {
  sixbt(B[d]); sixbt(B[d+1]); space(); sixbt(B[d+2]);
}

void dir () {
int i,d,m,u;
  for (i=1; i<=24; i++) {
    d = filedesc(i); m = bitmap(i); u = blocksused(m);
    if (u || B[d+3]&0400000) {
      printf("%02d %3d ",i,u); printname(d); newline();
    }
  }
  printf("%11d\n",blocksused(0));
}

void decfile (int start) {
int p,lim,pairs,mangled=0,next;
  while (start>0) {
/*fprintf(stderr,"//Next block %o\n",start);*/
    p = start*256; lim = p+254;
    while (p<lim) {
/*fprintf(stderr,"//Block %o Word %o %06o\n",p>>8,p&255,B[p]);*/
      if (B[p]==0) break;
      if (B[p]==01005) break;
      if ((B[p]&0777)!=2) die("DEC format mode not 2",p);
      pairs = B[p]>>9; p += 2;
      while(--pairs>0) {
        if (p>=lim) die("DEC record error",p-lim);
        dec5(B[p],B[p+1]); p += 2;
      }
    }
    next = B[lim+1];
    if (mangled) mangleblock(start);
    if (next<start) {
      mangled = 1; mangleblock(next);
    }
    start = next; if (start>=01100) start = -1;
  }
}

void aa1file (int start) {
int p,lim,sum=010161,w,mangled=0,next;
  while (start>0) {
    p = start*256; lim = p+255;
/*fprintf(stderr,"Block %o %o:%o %06o %06o sum %06o\n",*/
/*start,p,lim,B[p],B[lim],sum);*/
    if (B[p++]!=(sum&0777777)) die("AA1 checksum error",p-1);
    while (p<lim) {
      w = B[p++]; sum += w;
      aa1(w);
    }
    next = B[lim];
    if (mangled) mangleblock(start);
    if (next<start) {
      mangled = 1; mangleblock(next);
    }
    start = next; if (start>=01100) start = -1;
  }
}   

main (int c, char *v[]) {
int size=576*256*4;
int i,f;
FILE *tape,*origstdout;
  origstdout = stdout; stdout = stderr;

  B = (int*) malloc(size);

  if (c<2) die ("No tape file name",c);
  tape = fopen(v[1],"rb");
  if (tape==0) die("No tape file",0);
  i = fread(B,1,size,tape);
  printf("Got %d out of %d bytes\n\n",i,size);

  printf("Directory\n\n");
  dir();
  scanf("%d",&i); if (i==0) exit(0);
  printf("Going for file %d\n",i);
  f = i; if (i<0) i =-i;
  i = filedesc(i);
  printf("That's file "); printname(i);
  i = B[i+3];
  printf(", First block %o\n",i);
  stdout = origstdout;
  i = i&01777;
  if (f<0) {aa1file(i);} else decfile(i);
}
