/*
	GIER saveload

	(C) Copyright 2001 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 <fcntl.h>
#include <signal.h>
#include <string.h>
#include <time.h>

#include "GIER.h"
#include "common.h"

typedef struct
{
  char *name;
  int elementsize;
  int hasbeenread;
  void *ptr;
} Field;

static int Mode_value, Mode_drumsave_value;
static int kb1_visible, kb2_visible, typewriter_visible, reader_visible, punch_visible, printer_visible,
  plotter_visible, nimbi_visible, last_drum=-1;

extern void progress_init(int, char *);
extern void progress_stop();
extern int kb1_is_visible();
extern int kb2_is_visible();
extern int typewriter_is_visible();
extern int reader_is_visible();
extern int punch_is_visible();
extern int printer_is_visible();
extern int plotter_is_visible();
extern int nimbi_is_visible();
extern void progress_setvalue(int);
extern void checkdebug();
extern void kb2_init();
extern void kb2_destroy();
extern void kb1_init();
extern void kb1_destroy();
extern void typewriter_init();
extern void typewriter_destroy();
extern void reader_init();
extern void reader_destroy();
extern void punch_init();
extern void punch_destroy();
extern void printer_init();
extern void printer_destroy();
extern void plotter_init();
extern void plotter_destroy();
extern void nimbi_init();
extern void nimbi_destroy();
extern void typewriter_wait(int);
extern void reader_wait(int);

static Field fields[]=
{
  {"LI", sizeof(LI), 0, &LI},
  {"OR", sizeof(OR), 0, &OR},
  {"MD", sizeof(MD), 0, &MD},
  {"H", sizeof(H), 0, &H},
  {"MQ", sizeof(MQ), 0, &MQ},
  {"AC", sizeof(AC), 0, &AC},
  {"AD0", sizeof(AD0), 0, &AD0},
  {"AD1", sizeof(AD1), 0, &AD1},
  {"IN", sizeof(IN), 0, &IN},
  {"OT", sizeof(OT), 0, &OT},
  {"AD2", sizeof(AD2), 0, &AD2},
  {"SR", sizeof(SR), 0, &SR},
  {"TK", sizeof(TK), 0, &TK},
  {"TG", sizeof(TG), 0, &TG},
  {"BL", sizeof(BL), 0, &BL},
  {"BY", sizeof(BY), 0, &BY},
  {"BS", sizeof(BS), 0, &BS},
  {"BT", sizeof(BT), 0, &BT},
  {"TD", sizeof(TD), 0, &TD},
  {"TBA", sizeof(TBA), 0, &TBA},
  {"Tromle_size", sizeof(Tromle_size), 0, &Tromle_size},
  {"track0_open", sizeof(track0_open), 0, &track0_open},
  {"track1_31_open", sizeof(track1_31_open), 0, &track1_31_open},
  {"testmode", sizeof(testmode), 0, &testmode},
  {"sound_enabled", sizeof(sound_enabled), 0, &sound_enabled},
  {"reader_parity_error", sizeof(reader_parity_error), 0, &reader_parity_error},
  {"kb1_visible", sizeof(kb1_visible), 0, &kb1_visible},
  {"kb2_visible", sizeof(kb2_visible), 0, &kb2_visible},
  {"typewriter_visible", sizeof(typewriter_visible), 0, &typewriter_visible},
  {"reader_visible", sizeof(reader_visible), 0, &reader_visible},
  {"punch_visible", sizeof(punch_visible), 0, &punch_visible},
  {"printer_visible", sizeof(printer_visible), 0, &printer_visible},
  {"plotter_visible", sizeof(plotter_visible), 0, &plotter_visible},
  {"nimbi_visible", sizeof(nimbi_visible), 0, &nimbi_visible},
  {"Mode", sizeof(Mode_value), 0, &Mode_value},
  {"Mode_drumsave", sizeof(Mode_drumsave_value), 0, &Mode_drumsave_value},
  {"ind_ka", sizeof(ind_ka), 0, &ind_ka},
  {"ind_kb", sizeof(ind_kb), 0, &ind_kb},
  {"switch_k0", sizeof(switch_k0), 0, &switch_k0},
  {"aarhus_mode", sizeof(aarhus_mode), 0, &aarhus_mode},
  {"debug", sizeof(debug), 0, &debug},
  {"MA", sizeof(MA), 0, &MA},
  {"TO_error", sizeof(TO_error), 0, &TO_error},
  {"TR_error", sizeof(TR_error), 0, &TR_error},
  {"LI_drum", sizeof(LI_drum), 0, &LI_drum},
  {"TA", sizeof(TA), 0, &TA},
  {"drumsave_MA", sizeof(drumsave_MA), 0, &drumsave_MA},
  {"Mode_drumsave_value", sizeof(Mode_drumsave_value), 0, &Mode_drumsave_value},
  {"disk_cylinder", sizeof(disk_cylinder), 0, &disk_cylinder},
  {"disk_status", sizeof(disk_status), 0, &disk_status},
  {"disk_count", sizeof(disk_count), 0, &disk_count},
  {"last_disk_count", sizeof(last_disk_count), 0, &last_disk_count},
  {"drum_count", sizeof(drum_count), 0, &drum_count},
  {"drum_running", sizeof(drum_running), 0, &drum_running},
  {"drum_mode", sizeof(drum_mode), 0, &drum_mode},
  {"drum_address", sizeof(drum_address), 0, &drum_address},
  {"drum_cell_count", sizeof(drum_cell_count), 0, &drum_cell_count},
  {"YE_wait", sizeof(YE_wait), 0, &YE_wait},
  {"running", sizeof(running), 0, &running},
  {"spild", sizeof(spild), 0, &spild},
  {"h", sizeof(h), 0, &h},
  {"b", sizeof(b), 0, &b},
  {"c", sizeof(c), 0, &c},
  {"Select1", sizeof(selected_out[1]), 0, &selected_out[1]},
  {"Select2", sizeof(selected_out[2]), 0, &selected_out[2]},
  {"Select3", sizeof(selected_out[3]), 0, &selected_out[3]},
  {"Select4", sizeof(selected_out[4]), 0, &selected_out[4]},
  {"", 0, 0, NULL}
};

int GIER_save(char *filename)
{
  FILE *fp;
  int ifield,i,j,k;
  int progress;
  int max_progress;

  fp = fopen(filename, "w");

  if(fp == NULL) return 0;

  progress=0;
  max_progress = sizeof(fields)/sizeof(fields[0]) + 1024 + Tromle_size*40;
  if(Buffer != NULL)
  {
    max_progress += 4096;
    for(i=0; i<MAXBDISKS; i++)
    {
      if(BDisk_present[i])
      {
	max_progress += BDisk_size[i]*BDisk_tracksize[i];
      }
    }
    for(i=0; i<MAXBTAPES; i++)
    {
      /* 3 lines for each tape drive */
      max_progress += 3;
      if(BTape_len[i]>0)
      {
	/* 3 lines for each tape block */
	max_progress += 3*BTape_len[i];
	for(j=0; j<BTape_len[i]; j++)
	{
	  btapeblock *cur = &BTape[i][j];
	  if(cur->block != NULL) max_progress += cur->len;
	}
      }
    }
    for(i=0;i<CARROUSELREELS;i++)
    {
      for(j=0;j<CARROUSELBLOCKS;j++)
      {
	if(BCarr[i][j] != NULL) max_progress += CARROUSELWORDS;
      }
    }
  }

  progress_init(max_progress, "Saving file");

  if(Mode == Mode1) Mode_value=1;
  if(Mode == Mode2) Mode_value=2;
  if(Mode == Mode3) Mode_value=3;
  if(Mode == Mode4) Mode_value=4;
  if(Mode == Mode5) Mode_value=5;
  if(drumsave_Mode == Mode1) Mode_drumsave_value=1;
  if(drumsave_Mode == Mode2) Mode_drumsave_value=2;
  if(drumsave_Mode == Mode3) Mode_drumsave_value=3;
  if(drumsave_Mode == Mode4) Mode_drumsave_value=4;
  if(drumsave_Mode == Mode5) Mode_drumsave_value=5;
  kb1_visible = kb1_is_visible();
  kb2_visible = kb2_is_visible();
  typewriter_visible = typewriter_is_visible();
  reader_visible = reader_is_visible();
  punch_visible = punch_is_visible();
  printer_visible = printer_is_visible();
  plotter_visible = plotter_is_visible();
  nimbi_visible = nimbi_is_visible();

  for(ifield=0; fields[ifield].name[0] != '\0'; ifield++)
  {
    progress_setvalue(progress++);
    fprintf(fp, "%s\t", fields[ifield].name);
    if(fields[ifield].elementsize == 2)
      fprintf(fp, "%4.4hX\n", *(unsigned short *) (fields[ifield].ptr));
    if(fields[ifield].elementsize == 4)
      fprintf(fp, "%8.8X\n", *(unsigned int *) (fields[ifield].ptr));
    if(fields[ifield].elementsize == 8)
#ifdef WINDOWS
      fprintf(fp, "%16.16I64X\n", *(unsigned long long *) (fields[ifield].ptr));
#else
      fprintf(fp, "%16.16llX\n", *(unsigned long long *) (fields[ifield].ptr));
#endif
  }

  for(i=0; i<1024; i++)
  {
    progress_setvalue(progress++);
    if(Ferrit[i] != 0ULL)
#ifdef WINDOWS
      fprintf(fp, "Ferrit[%d]\t%16.16I64X\n", i, Ferrit[i]);
#else
      fprintf(fp, "Ferrit[%d]\t%16.16llX\n", i, Ferrit[i]);
#endif
  }

  for(i=0; i<Tromle_size*40; i++)
  {
    progress_setvalue(progress++);
    if(Tromle[i] != 0ULL)
#ifdef WINDOWS
      fprintf(fp, "Tromle[%d]\t%16.16I64X\n", i, Tromle[i]&ONE0_41);
#else
      fprintf(fp, "Tromle[%d]\t%16.16llX\n", i, Tromle[i]&ONE0_41);
#endif
  }

  if(Buffer != NULL)
  {
    for(i=0; i<4096; i++)
    {
      progress_setvalue(progress++);
      if(Buffer[i] != 0ULL || i == 0)
#ifdef WINDOWS
	fprintf(fp, "Buffer[%d]\t%16.16I64X\n", i, Buffer[i]);
#else
	fprintf(fp, "Buffer[%d]\t%16.16llX\n", i, Buffer[i]);
#endif
    }
    for(i=0; i<MAXBDISKS; i++)
    {
      if(BDisk_present[i])
      {
        fprintf(fp, "BDisk%d_tracksize\t%8.8X\n", i+8, BDisk_tracksize[i]);
        fprintf(fp, "BDisk%d_size\t%8.8X\n", i+8, BDisk_size[i]);
	for(j=0; j<BDisk_size[i]*BDisk_tracksize[i]; j++)
	{
	  progress_setvalue(progress++);
	  if(BDisk[i][j] != 0ULL || j == 0)
	  {
#ifdef WINDOWS
	    fprintf(fp, "BDisk%d[%d]\t%16.16I64X\n", i+8, j, BDisk[i][j]);
#else
	    fprintf(fp, "BDisk%d[%d]\t%16.16llX\n", i+8, j, BDisk[i][j]);
#endif
	  }
	}
      }
    }
    for(i=0; i<MAXBTAPES; i++)
    {
      /* 3 lines for each tape drive */
      progress_setvalue(progress++);
      fprintf(fp, "BTape_len%d\t%d\n", i+1, BTape_len[i]);
      progress_setvalue(progress++);
      fprintf(fp, "BTape_current%d\t%d\n", i+1, BTape_current[i]);
      progress_setvalue(progress++);
#ifdef WINDOWS
      fprintf(fp, "BTape_status%d\t%16.16I64X\n", i+1, BTape_status[i]);
#else
      fprintf(fp, "BTape_status%d\t%16.16llX\n", i+1, BTape_status[i]);
#endif
      if(BTape_len[i]>0)
      {
	/* 3 lines for each tape block */
	max_progress += 3*BTape_len[i];
	for(j=0; j<BTape_len[i]; j++)
	{
	  btapeblock *cur = &BTape[i][j];
	  progress_setvalue(progress++);
	  fprintf(fp, "BTape_blocklen%d[%d]\t%d\n", i+1, j, cur->len);
	  progress_setvalue(progress++);
	  fprintf(fp, "BTape_wordlen%d[%d]\t%d\n", i+1, j, cur->wordlen);
	  progress_setvalue(progress++);
	  fprintf(fp, "BTape_parity%d[%d]\t%d\n", i+1, j, cur->parity);
	  if(cur->block != NULL)
	  {
	    for(k=0; k<cur->len; k++)
	    {
	      progress_setvalue(progress++);
#ifdef WINDOWS
	      fprintf(fp, "BTape_block%d[%d][%d]\t%16.16I64X\n", i+1, j, k, cur->block[k]);
#else
	      fprintf(fp, "BTape_block%d[%d][%d]\t%16.16llX\n", i+1, j, k, cur->block[k]);
#endif
	    }
	  }
	}
      }
    }
    for(i=0;i<CARROUSELREELS;i++)
    {
      for(j=0;j<CARROUSELBLOCKS;j++)
      {
	if(BCarr[i][j] != NULL)
	{
	  for(k=0;k<CARROUSELWORDS;k++)
	  {
#ifdef WINDOWS
	    fprintf(fp, "BCarr[%d][%d][%d]\t%16.16I64X\n", i, j, k, BCarr[i][j][k]);
#else
	    fprintf(fp, "BCarr[%d][%d][%d]\t%16.16llX\n", i, j, k, BCarr[i][j][k]);
#endif
	  }
	}
      }
    }
  }

  progress_stop();

  fclose(fp);
  return 1;
}

int GIER_load(char *filename)
{
  FILE *fp;
  int ifield, i, j, k, bdisk, tapeno;
  char buf[1024];
  char *bp,*cp,*cp2;
  int error_occured;
  int iline;

  fprintf(stderr, "GIER_load: %s\n", filename);

  fp = fopen(filename, "r");

  if(fp == NULL) return 0;

  /* Store state as it is */
  kb1_visible = kb1_is_visible();
  kb2_visible = kb2_is_visible();
  typewriter_visible = typewriter_is_visible();
  reader_visible = reader_is_visible();
  punch_visible = punch_is_visible();
  printer_visible = printer_is_visible();
  plotter_visible = plotter_is_visible();
  nimbi_visible = nimbi_is_visible();

  selected_out[1] = 8;
  selected_out[2] = 16;
  selected_out[3] = 32;
  selected_out[4] = 64;

  for(ifield=0; fields[ifield].name[0] != '\0'; ifield++) fields[ifield].hasbeenread = 0;
  Mode_value = 0;
  TR_error = 0;
  LI_drum = 0ULL;
  TA=0;
  drumsave_MA=1;
  Mode_drumsave_value = 0;
  disk_status = 0;
  disk_cylinder = 0;
  last_disk_count = 0;
  disk_count = 0;
  drum_count = 0;
  drum_running = 0;
  drum_mode = 0;
  drum_address = 0;
  drum_cell_count = 0;

  fseek(fp, 0, SEEK_END);
  progress_init(ftell(fp), "Loading file");
  fseek(fp, 0, SEEK_SET);
  iline=0;

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

    if((iline++)%500==0)progress_setvalue(ftell(fp));

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

    if(!strncmp(cp, "Ferrit[", 7))
    {
      sscanf(cp+7, "%d", &i);
      cp=strtok(0, "\t\n");
#ifdef WINDOWS
      sscanf(cp, "%I64x", Ferrit+i);
#else
      sscanf(cp, "%llx", Ferrit+i);
#endif
    }
    else if(!strncmp(cp, "Tromle[", 7))
    {
      sscanf(cp+7, "%d", &i);

      if(i == -1)
      {
	i = last_drum+1;
      }
      
      if(i > Tromle_size*40)
      {
        fprintf(stderr, "Tromle element is outside drum (%d > %d).\n", i, Tromle_size*40);
	fclose(fp);
	return 0;
      }
      cp=strtok(0, "\t\n");
#ifdef WINDOWS
      sscanf(cp, "%I64x", Tromle+i);
#else
      sscanf(cp, "%llx", Tromle+i);
#endif
      Tromle[i] &= ONE0_41;
      last_drum = i;
    }
    else if(!strncmp(cp, "Buffer[", 7))
    {
      sscanf(cp+7, "%d", &i);
      
      if(i > 4095)
      {
        fprintf(stderr, "Buffer element is outside buffer (%d > 4095).\n", i);
	fclose(fp);
	return 0;
      }
      if(Buffer==NULL)
      {
        Buffer = (GIERword *) malloc(sizeof(*Buffer)*4096);
	for(j=0; j<4096; j++) Buffer[i] = 0ULL;
      }
      cp=strtok(0, "\t\n");
#ifdef WINDOWS
      sscanf(cp, "%I64x", Buffer+i);
#else
      sscanf(cp, "%llx", Buffer+i);
#endif
    }
    else if(!strncmp(cp, "BDisk", 5))
    {
      cp2 = cp+5;
      bdisk = *(cp2++)-'0';
      if(bdisk==1) bdisk=bdisk*10+*(cp2++)-'0';
      if(*cp2 == '_')
      {
	cp2++;
	cp=strtok(0, "\t\n");
	if(!strncmp(cp2, "tracksize", 9))
	{
	  sscanf(cp, "%x", &BDisk_tracksize[bdisk-8]);
	}
	else if(!strncmp(cp2, "size", 4))
	{
	  sscanf(cp, "%x", &BDisk_size[bdisk-8]);
	}
      }
      else if(*cp2 == '[')
      {
	cp2++;
	sscanf(cp2, "%d", &i);
	if(BDisk[bdisk-8]==NULL)
	{
	  if(BDisk_tracksize[bdisk-8]==0 || BDisk_size[bdisk-8]==0)
	  {
	    fprintf(stderr, "Buffer disk %d element present, but no tracksize or size present.\nAssuming CDC 854, 2030 tracks of 600 words", bdisk);
	    BDisk_tracksize[bdisk-8]=600;
	    BDisk_size[bdisk-8]=2030;
	  }
	  BDisk[bdisk-8] = (GIERword *) malloc(sizeof(**BDisk)*BDisk_tracksize[bdisk-8]*BDisk_size[bdisk-8]);
	  for(j=0; j<BDisk_tracksize[bdisk-8]*BDisk_size[bdisk-8]; j++)
	    BDisk[bdisk-8][j] = 0ULL;
          BDisk_present[i]=1;
	}
	if(i>=BDisk_tracksize[bdisk-8]*BDisk_size[bdisk-8])
	{
	  fprintf(stderr, "Buffer disk %d element %d outsize limit: %d\n", bdisk, i, BDisk_tracksize[bdisk-8]*BDisk_size[bdisk-8]);
	  fclose(fp);
	  return 0;
	}
	cp=strtok(0, "\t\n");
#ifdef WINDOWS
	sscanf(cp, "%I64x", &BDisk[bdisk-8][i]);
#else
	sscanf(cp, "%llx", &BDisk[bdisk-8][i]);
#endif
      }
    }
    else if(!strncmp(cp, "BTape_len", 9))
    {
      cp2 = cp+9;
      tapeno = *(cp2++)-'0';
      cp2++;
      for(i=0; i<BTape_len[tapeno-1]; i++)
      {
	if(BTape[tapeno-1][i].block!=NULL)
	{
	  free(BTape[tapeno-1][i].block);
	  BTape[tapeno-1][i].block = NULL;
	}
      }
      sscanf(cp2, "%d", &BTape_len[tapeno-1]);
      if(BTape_len[tapeno-1]>0)
      {
	BTape[tapeno-1] = realloc(BTape[tapeno-1], sizeof(**BTape)*BTape_len[tapeno-1]);
      }
      else
      {
	BTape[tapeno-1] = NULL;
      }
      for(i=0; i<BTape_len[tapeno-1]; i++)
      {
	BTape[tapeno-1][i].len = 0;
	BTape[tapeno-1][i].wordlen = 0;
	BTape[tapeno-1][i].parity = 0;
	BTape[tapeno-1][i].block = NULL;
      }
    }
    else if(!strncmp(cp, "BTape_current", 13))
    {
      cp2 = cp+13;
      tapeno = *(cp2++)-'0';
      cp2++;
      sscanf(cp2, "%d", &BTape_current[tapeno-1]);
    }
    else if(!strncmp(cp, "BTape_status", 12))
    {
      cp2 = cp+12;
      tapeno = *(cp2++)-'0';
      cp2++;
#ifdef WINDOWS
      sscanf(cp2, "%I64x", &BTape_status[tapeno-1]);
#else
      sscanf(cp2, "%llx", &BTape_status[tapeno-1]);
#endif
    }
    else if(!strncmp(cp, "BTape_blocklen", 14))
    {
      cp2 = cp+14;
      tapeno = *(cp2++)-'0';
      if(*(cp2++) == '[')
      {
	sscanf(cp2, "%d", &i);
	cp=strtok(0, "\t\n");
	sscanf(cp, "%d", &(BTape[tapeno-1][i].len));
	BTape[tapeno-1][i].block = malloc(sizeof(GIERword)*BTape[tapeno-1][i].len);
      }
    }
    else if(!strncmp(cp, "BTape_wordlen", 13))
    {
      cp2 = cp+13;
      tapeno = *(cp2++)-'0';
      if(*(cp2++) == '[')
      {
	sscanf(cp2, "%d", &i);
	cp=strtok(0, "\t\n");
	sscanf(cp, "%d", &(BTape[tapeno-1][i].wordlen));
      }
    }
    else if(!strncmp(cp, "BTape_parity", 12))
    {
      cp2 = cp+12;
      tapeno = *(cp2++)-'0';
      if(*(cp2++) == '[')
      {
	sscanf(cp2, "%d", &i);
	cp=strtok(0, "\t\n");
	sscanf(cp, "%d", &(BTape[tapeno-1][i].parity));
      }
    }
    else if(!strncmp(cp, "BTape_block", 11))
    {
      cp2 = cp+11;
      tapeno = *(cp2++)-'0';
      if(*(cp2++) == '[')
      {
	sscanf(cp2, "%d", &i);
	while(*(cp2++) != '[');
	sscanf(cp2, "%d", &j);
	cp=strtok(0, "\t\n");
#ifdef WINDOWS
	sscanf(cp, "%I64x", &(BTape[tapeno-1][i].block[j]));
#else
	sscanf(cp, "%llx", &(BTape[tapeno-1][i].block[j]));
#endif
      }
    }
    else if(!strncmp(cp, "BCarr", 5))
    {
      cp2 = cp+5;
      if(*(cp2++) == '[')
      {
	sscanf(cp2, "%d", &i);
	while(*(cp2++) != '[');
	sscanf(cp2, "%d", &j);
	if(BCarr[i][j] == NULL)
	  BCarr[i][j] = malloc(sizeof(GIERword)*CARROUSELWORDS);
	while(*(cp2++) != '[');
	sscanf(cp2, "%d", &k);
	cp=strtok(0, "\t\n");
#ifdef WINDOWS
	sscanf(cp, "%I64x", &(BCarr[i][j][k]));
#else
	sscanf(cp, "%llx", &(BCarr[i][j][k]));
#endif
      }
    }
    else
    {
      for(ifield=0; fields[ifield].name[0] != '\0'; ifield++)
      {
        if(!strcmp(cp, fields[ifield].name))
	{
	  cp=strtok(0, "\t\n");
	  if(fields[ifield].elementsize == 2)
	  {
            sscanf(cp, "%hx", (unsigned short *) (fields[ifield].ptr));
	  }
	  else if(fields[ifield].elementsize == 4)
	  {
            sscanf(cp, "%x", (unsigned int *) (fields[ifield].ptr));
	    if(!strcmp(fields[ifield].name,"debug")) checkdebug();
	  }
	  else if(fields[ifield].elementsize == 8)
	  {
#ifdef WINDOWS
            sscanf(cp, "%I64x", (unsigned long long *) (fields[ifield].ptr));
#else
            sscanf(cp, "%llx", (unsigned long long *) (fields[ifield].ptr));
#endif
	  }
	  fields[ifield].hasbeenread = 1;
          if(!strcmp(fields[ifield].name,"Tromle_size"))
	  {
	    free((char *) Tromle);
	    Tromle=(GIERword *) malloc(sizeof(*Tromle)*40*Tromle_size);
	    for(i=0; i<Tromle_size*40; i++) Tromle[i] = 0ULL;
	    /* We also clear the core store */
	    for(i=0; i<1024; i++) Ferrit[i] = 0ULL;
	  }
	}
      }
    }
  }
  
  progress_stop();
  fclose(fp);

  if(Mode_value == 1) Mode=Mode1;
  if(Mode_value == 2) Mode=Mode2;
  if(Mode_value == 3) Mode=Mode3;
  if(Mode_value == 4) Mode=Mode4;
  if(Mode_value == 5) Mode=Mode5;

  for(ifield=0; fields[ifield].name[0] != '\0'; ifield++)
  {
    if(!fields[ifield].hasbeenread)
    {
      memset((char *) (fields[ifield].ptr), 0, fields[ifield].elementsize);
    }
  }

  if(kb2_visible != kb2_is_visible())
  {
    if(kb2_visible)
    {
      if(debug&DEBUGinterface)
      {
	fprintf(debug_fh, "kb2_init called from saveload\n");
	fflush(debug_fh);
      }
      kb2_init();
    }
    else
    {
      kb2_destroy();
    }
  }

  if(kb1_visible != kb1_is_visible())
  {
    if(kb1_visible)
    {
      if(debug&DEBUGinterface)
      {
	fprintf(debug_fh, "kb1_init called from saveload\n");
	fflush(debug_fh);
      }
      kb1_init();
      if(debug&DEBUGinterface)
      {
	fprintf(debug_fh, "kb1_init returned to saveload\n");
	fflush(debug_fh);
      }
    }
    else
    {
      kb1_destroy();
    }
  }

  if(typewriter_visible != typewriter_is_visible())
  {
    if(typewriter_visible)
    {
      typewriter_init();
    }
    else
    {
      typewriter_destroy();
    }
  }

  if(reader_visible != reader_is_visible())
  {
    if(reader_visible)
    {
      reader_init();
    }
    else
    {
      reader_destroy();
    }
  }

  if(punch_visible != punch_is_visible())
  {
    if(punch_visible)
    {
      punch_init();
    }
    else
    {
      punch_destroy();
    }
  }

  if(printer_visible != printer_is_visible())
  {
    if(printer_visible)
    {
      printer_init();
    }
    else
    {
      printer_destroy();
    }
  }

  if(plotter_visible != plotter_is_visible())
  {
    if(plotter_visible)
    {
      plotter_init();
    }
    else
    {
      plotter_destroy();
    }
  }

  if(nimbi_visible != nimbi_is_visible())
  {
    if(nimbi_visible)
    {
      nimbi_init();
    }
    else
    {
      nimbi_destroy();
    }
  }


  if(YE_wait)
  {
    if(((BY&2)&&(!(BY&1)))||((!(BY&2))&&(BY&1)))
    {
      typewriter_wait(TRUE);
    }
    else
    {
      reader_wait(TRUE);
    }
  }

  /* Insert date and clear run number */

  for(i=0;i<Tromle_size;i++)
  {
    if((Tromle[i*40+2]&ONE0_39)==0x0000028A2B5D69D8ULL)
    {
      /* Found catalog with free entry */
      for(j=3;j<40;j++)
      {
	if((Tromle[i*40+j]&ONE0_39)==0x0000028A2A2A6658ULL)
	{
	  /* Found date entry */
	  GIERword olddate,oldrun,oldsum,newdate,newrun,newsum,year,month,day;
	  struct tm *ltm;
	  time_t curtime;
	  olddate = Tromle[i*40+j+1];
	  oldrun = Tromle[i*40+j+2];
	  oldsum = Tromle[i*40+39];
	  time(&curtime);
	  ltm=localtime(&curtime);
	  year = ltm->tm_year-100;
	  month = ltm->tm_mon+1;
	  day = ltm->tm_mday;
	  newdate = (((day<<20)|(month<<10)|year)<<2)|0x60000000002ULL;
	  newrun = 0x0000000000000002ULL;
	  newsum = oldsum-newdate+olddate-newrun+oldrun;
	  Tromle[i*40+j+1] = newdate;
	  Tromle[i*40+j+2] = newrun;
	  Tromle[i*40+39] = newsum;
	  fprintf(stderr, "Setting date %d.%d.%d in track %d, cell %d\n", (int)day, (int)month, (int)year, i, j);
	  goto finish;
	}
      }
    }
  }
finish:
  return 1;
}
