
/*
	GIER simulator - Print Help 3 catalog

	(C) Copyright 2001-2011 by Mogens Kjaer


   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include "GIER.h"

#define MARKa ONE40
#define MARKb ONE41
#define MARKc ONE40_41
#define MARKS ONE40_41

static GIERword Tromle[960*40*10],c;
static int track,cell,catlen;
static GIERword checksum;
static int reltrack=1;
static int BDisk_tracksize[16],BDisk_size[16];
#define ADDER(a,b) ((((a)&ONE0_39)+((b)&ONE0_39))&ONE0_39)

extern unsigned char flx2a(char, int *);

GIERword nextcell()
{
  GIERword c;
  while(1)
  {
    c=Tromle[cell++];
    checksum=ADDER(checksum,c);
    if(c&ONE40)
      checksum=ADDER(checksum,ONE8);
    if(c&ONE41)
      checksum=ADDER(checksum,ONE9);
//  printf("\nnext cell: %d %llx %s %s\n", cell-1, c, (c&ONE40)?"A":"", (c&ONE41)?"B":"");
    /* Test for last cell on track, c-marked */
    if((c&ONE40_41)==ONE40_41)
    {
      checksum=ADDER(checksum,((GIERword)reltrack)<<SHIFT9);
      reltrack++;
      if(checksum==0)
      {
//	printf("\nchecksum OK\n");
      }
      else
      {
	printf("\nreltrack: %d checksum BAD: %16.16llX\n",reltrack,checksum);
      }
      checksum=0;
      continue;
    }
    /* Test for deleted item */
//  if(c==0) continue;
    /* Test for end of catalog */
    if(((c&ONE0_39)==0)&((c&MARKS)==MARKb))
    {
      printf("\n");
      exit(0);
    }
    break;
  }
  return c;
}

int main(int argc, char **argv)
{
  FILE *fp;
  char buf[1024];
  char ch1,ch2;
  int uc,i,kind,s,done,unit;
  char *bp,*cp;

  if(argc<2)
  {
    fprintf(stderr, "Usage: catalogdump file.gier firsttrack\n");
    exit(-1);
  }

  fp = fopen(argv[1], "r");

  if(fp == NULL)
  {
    fprintf(stderr, "Could not open %s for reading.\n", argv[1]);
    exit(-1);
  }

  for(i=0;i<40*960*10;i++) Tromle[i] = 0ULL;
  for(i=0;i<16;i++)
  {
    BDisk_tracksize[i] = -1;
    BDisk_size[i] = -1;
  }

  while(1)
  {
    bp = fgets(buf, sizeof(buf), fp);
    if(bp == NULL) break;

    cp=strtok(bp, "\t\n");
    if(!cp) continue;

    if(!strncmp(cp, "Tromle[", 7))
    {
      sscanf(cp+7, "%d", &i);
      cp=strtok(0, "\t\n");
      if(i<960*40*10)
      {
#ifdef WINDOWS
	sscanf(cp, "%I64x", Tromle+i);
#else
	sscanf(cp, "%llx", Tromle+i);
#endif
      }
    }
    else if(!strncmp(cp, "BDisk", 5))
    {
      unit=cp[5]-'0';
      if(!strncmp(cp+7, "tracksize", 9))
      {
	cp=strtok(0, "\t\n");
	sscanf(cp, "%X", BDisk_tracksize+unit);
      }
      else if(!strncmp(cp+7, "size", 4))
      {
	cp=strtok(0, "\t\n");
	sscanf(cp, "%X", BDisk_size+unit);
      }

    }
  }
  fclose(fp);

  for(i=0;i<16;i++)
  {
    if(BDisk_tracksize[i] != -1)
    {
      printf("Disk unit %d: %d tracks of %d words.\n", i, BDisk_size[i], BDisk_tracksize[i]);
    }
  }
  track=0;
  for(i=9599;i>0;i--)
  {
    if((Tromle[i*40+2]&ONE0_39)==0x0000028A2B5D69D8ULL)
    {
      printf("Catalog \"free\" entry on track %d\n", i);
      track=i;
    }
  }

  if(argc>2) track=atoi(argv[2]);

  if(track==0)
  {
    printf("No catalog found.\n");
    exit(0);
  }

  cell = 40*track;

  catlen = (Tromle[cell+1]&ONE0_7)>>SHIFT7;
  checksum=0;
  reltrack=1;
  done=0;

  for(i=0;(i<catlen)&&(!done);i++)
  {
    cell=40*(track+i);
//    printf("Track %4d: ",track+i);
next:
    c=Tromle[cell++];
    if(((c&ONE0_39)==0)&((c&MARKS)==MARKb)) done=1;
    checksum=ADDER(checksum,c);
    if(c&ONE40)
      checksum=ADDER(checksum,ONE8);
    if(c&ONE41)
      checksum=ADDER(checksum,ONE9);
    /* printf("\nnext cell: %d %llx\n", cell-1, c); */
    /* Test for last cell on track, c-marked */
    if((c&ONE40_41)==ONE40_41)
    {
      checksum=ADDER(checksum,((GIERword)reltrack)<<SHIFT9);
      if(checksum==0)
      {
        printf("checksum OK track %d\n",reltrack);
      }
      else
      {
	printf("track: %d catlen: %d reltrack: %d checksum BAD: %16.16llX\n",track,catlen,reltrack,checksum);
      }
      reltrack++;
      checksum=0;
      continue;
    }
    goto next;
  }
  checksum=0;
  reltrack=1;
  cell = 40*track;

  c = nextcell();
  while(1)
  {
    if(c==0)
    {
      printf("======== Track %d Cell %d DELETED\n", (cell-1)/40, (cell-1)%40);
      c = nextcell();
    }
    if((c&MARKS)==MARKa)
    {
      /* Area word */
      printf("======== Track %d Cell %d\n", (cell-1)/40, (cell-1)%40);
      kind = (c&ONE0_2)>>SHIFT2;
      printf("Kind: %d ", kind);
      switch(kind)
      {
	case 0:
	  s=(c&ONE8_23)>>SHIFT23;
	  printf(" drum area %d block%s starting at %d ",
	         s, s==1?"":"s", (int)((c&ONE24_39)>>SHIFT39));
	  break;
	case 1:
	  s=(c&ONE8_23)>>SHIFT23;
	  printf(" disc area %d block%s starting at %d on unit %d ",
	         s, s==1?"":"s", (int)((c&ONE28_39)>>SHIFT39), (int)((c&ONE24_27)>>SHIFT27));
	  break;
	case 2:
	  s=(c&ONE8_23)>>SHIFT23;
	  printf(" carroussel area %d block%s grouped %d reel %d block %d ",
	         s, s==1?"":"s", (int)((c&ONE28_29)>>SHIFT29), (int)((c&ONE30_35)>>SHIFT35), (int)((c&ONE36_39)>>SHIFT39));
	  break;
	case 3:
	  s=(c&ONE8_23)>>SHIFT23;
	  printf(" tape area %d block%s on unit %d file %d block %d ",
	         s, s==1?"":"s", (int)((c&ONE24_27)>>SHIFT27), (int)((c&ONE28_32)>>SHIFT32), (int)((c&ONE33_39)>>SHIFT39));
	  break;
	case 4:
	  printf(" constant: %d.%d.%d.%d\n", (int)((c&ONE1_9  )>>SHIFT9) , (int)((c&ONE10_19)>>SHIFT19),
				   (int)((c&ONE20_29)>>SHIFT29), (int)((c&ONE30_39)>>SHIFT39));
	  break;
	case 6:
	  printf(" sy medium: %d mask %d ", (int)((c&ONE10_19)>>SHIFT19), (int)((c&ONE20_29)>>SHIFT29));
	  break;
	case 7:
	  printf(" ly medium: %d mask %d ", (int)((c&ONE10_19)>>SHIFT19), (int)((c&ONE20_29)>>SHIFT29));
	  break;
      }
      if(c&ONE3) printf("Special ");
      if(c&ONE4) printf("Program ");
      if(c&ONE5) printf("Reserved ");
      if(c&ONE6) printf("Inhibit ");
      if(c&ONE7) printf("Sum ");
      printf(" help number: %d.%d.%d.%d\n", (int)((c&ONE0_9  )>>SHIFT9) , (int)((c&ONE10_19)>>SHIFT19),
				   (int)((c&ONE20_29)>>SHIFT29), (int)((c&ONE30_39)>>SHIFT39));
      c = nextcell();
      if((c&MARKS)==MARKa)
      {
	/* secondary word */
	printf(" %d.%d.%d.%d ", (int)((c&ONE0_9  )>>SHIFT9) , (int)((c&ONE10_19)>>SHIFT19),
	                         (int)((c&ONE20_29)>>SHIFT29), (int)((c&ONE30_39)>>SHIFT39));
	c = nextcell();
      }
      printf("\n");
      while((c&MARKS)!=MARKa)
      {
	if(c==0)
	{
	  break;
	}
	/* Print string */
	uc = 0;
	c = c&ONE0_39;
	while((ch1 = (char)((c&ONE34_39)>>SHIFT39))!=10)
	{
	  if(ch1==15)
	  {
	    c = nextcell()&ONE0_39;
	  }
	  else
	  {
	    if(ch1==63) ch1=64;
	    ch2 = flx2a(ch1, &uc);
	    if(ch2>=0 && ch2<255) printf("%c", ch2);
	    c = c>>6;
	  }
	}
	printf("  ");
	c = nextcell();
	if((c&ONE0)==0 && (c&MARKS)!=MARKa)
	{
	  /* specification word */
	  printf(" %d.%d.%d.%d ", (int)((c&ONE0_9  )>>SHIFT9) , (int)((c&ONE10_19)>>SHIFT19),
				   (int)((c&ONE20_29)>>SHIFT29), (int)((c&ONE30_39)>>SHIFT39));
	  c = nextcell();
	}
	printf("\n");
      }
    }
  }
}
