#include <stdio.h>
#include <string.h>
#include <stdlib.h>

/*
 * Convert SIMH simulator tapes to normal files
 *
 * Copyright 2016 Tom Vijlbrief
 *
 * tvijlbrief at gmail dot com
 *
 * Distributed under the GPL license
 */

void usage()
{
  fprintf(stderr, "usage: rdtape [-v] [-s skip]\n");
  exit(1);
}

int verbose;

/*
 read longword in little endian order from file
 */

long rl(FILE *f)
{
  unsigned char c[4];
  long len;
  static long prevlen, lencnt;

  if (fread(c, 1, 4, f) != 4) {
    fprintf(stderr, "Cannot read tape marker\n");
    exit(1);
  }
  len =
    ((long)c[0]) |
    ((long)c[1] << 8)  |
    ((long)c[2] << 16) |
    ((long)c[3] << 24);
  if (verbose) {
    if (len != prevlen) {
      lencnt= 0;
    } else {
      lencnt++;
      fprintf(stderr, "\r%05ldB %ld blocks", len, lencnt);
    }
  }
  prevlen = len;
  return len;
}

/*
 read from file and write unblocked data to stdout
 */

void rblock(FILE *f, FILE *out)
{
    size_t ret;
    void *b;
    long blen;

    while (!feof(f)) {
      blen = rl(f);
      if (!blen) {
        if (verbose)
	  fprintf(stderr, "\nend-of-file\n");
        break;
      }
      b = malloc(blen);
      if (b == NULL) {
        perror("malloc:");
        exit(1);
      }
      memset(b, 0, blen);
      ret = fread(b, 1, blen, f);
      if (ret != blen) {
	fprintf(stderr, "short tape block\n");
	exit(3);
      }
      if (fwrite(b, 1, blen, out) != blen) {
	fprintf(stderr, "write failed\n");
	exit(2);
      }
      if (rl(f) != blen) {
	fprintf(stderr, "non matching end of block marker\n");
	exit(3);
      }
      free(b);
    }
}

int main(int argc, char **argv)
{
  int i = 0;
  int skip = 0;
  int s;
  FILE *out;
  FILE *f;

  while (++i < argc) {

    f = 0;
    skip = 0;

    if (strcmp(argv[i], "-h") == 0){
      usage();
      exit(0);
    }

    if (strcmp(argv[i], "-v") == 0){
      verbose = 1;
      continue;
    }

    if (strcmp(argv[i], "-s") == 0){
      if (++i == argc) {
	usage();
        exit(1);
      }
      skip = atoi(argv[i++]);
      if (skip < 0) {
	usage();
	exit(1);
      }
      out = fopen("/dev/null", "w");
      f = fopen(argv[i], "r");
      if (f == NULL) {
        perror(argv[i]);
        exit(1);
      }
      for (s = 0; s < skip; s++)
        rblock(f, out);
      fclose(out);
    }

    if (!f) {
      f = fopen(argv[i], "r");
      if (f == NULL) {
        perror(argv[i]);
        exit(1);
      }
    }
    rblock(f, stdout);
    if (fclose(f) != 0) {
      perror(argv[i]);
      exit(1);
    }

  }

  return 0;
}

