/*
 * Copyright © 1994-1996 Marko Mäkelä and Olaf Seibert
 * Original Linux and Commodore 64/128/Vic-20 version by Marko Mäkelä
 * Ported to the PET and the Amiga series by Olaf Seibert
 * 
 *     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., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

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

#include "prtrans.h"

#if !defined(__MAIN_C__)
#define main    main_prsave
#endif

unsigned char buffer[65536];

static char *myname;

int main (int argc, char **argv);
unsigned prsave(int bank, int start, int end, unsigned char *buffer, int verbose);

int main (int argc, char **argv) {
  unsigned start, end, length;
  unsigned driveraddr, basicaddr;
  FILE *file = stdout;
  unsigned bank = 0;
  char **parameters = argv;
  baseaddr = portaddr[DEFAULT_PORT];

  myname = argv[0];

  while (*++parameters && **parameters == '-') { /* check for options */
    if (parameters[0][1] == '-') { /* "--" ends options */
      parameters++;
      break;
    }

    switch (parameters[0][1]) {
    case 'b':
      bank = strtoul (*++parameters, NULL, 16);

      if (bank > 255) {
	fprintf (stderr, "%s: Illegal memory bank specified.\n", myname);
	return 1;
      }

      break;

    case 'p':
      baseaddr = strtoul (*++parameters, NULL, 16);

      if (baseaddr > 3) {
	fprintf (stderr, "%s: The printer port number must be between 0 and 3.\n",
			 myname);
	return 1;
      }

      baseaddr = portaddr[baseaddr];

      break;

    case '?':
    case 'h':
    Usage:
      fprintf (stderr, "%s: Dumps a memory area on a remote "
		       "computer to a file or standard output.\n\n", myname);
      fprintf (stderr, "Usage: %s [options] startaddress endaddress [filename]\n",
		       myname);
      fprintf (stderr, "Options:\n\t"
			 "-b bank\t"
			     "Specify the memory bank (in hex)\n\t"
			 "-p port\t"
			     "Specify the printer port (0 to 3)\n");
      fprintf (stderr, "The start and end address may be prefixed with a @,\n"
		       "which fetches 2 bytes from the given address and uses\n"
		       "the result in place of the address.\n");
      prclose ();
      return 1;

    default:
      fprintf (stderr, "%s: Illegal option `%s'.\n", myname, *parameters);
      goto Usage;
    }
  }

  if (!*parameters) goto Usage;

  if (prinit()) {
    fprintf (stderr, "%s: Could not get the I/O permissions.\n", myname);
    return 4;
  }

  if (**parameters == '@') {
    unsigned char tmp[2];

    start = strtoul (&parameters[0][1], NULL, 16);
    end = start + 2;
    parameters++;
    prsave(0, start, start + 2, tmp, 0);
    start = tmp[0] | tmp[1] << 8;
    printf("Start at %04x\n", start);
  } else {
    start = strtoul (*parameters++, NULL, 16);
    end = start;
  }

  if (!*parameters) goto Usage;

  if (**parameters == '@') {
    unsigned char tmp[2];

    if (parameters[0][1] != '\0')
      end = strtoul (&parameters[0][1], NULL, 16);
    parameters++;
    prsave(0, end, end + 2, tmp, 0);
    end = tmp[0] | tmp[1] << 8;
    printf("End at %04x\n", end);
  } else
    end = strtoul (*parameters++, NULL, 16);

#ifdef WRAP_AROUND
  if (start & ~65535 || end & ~65535)
    goto Usage;
#else
  if (start & ~65535 || end & ~65535 || (start >= end && end))
    goto Usage;
#endif /* WRAP_AROUND */


  if (*parameters) { /* a file name was specified */
    if (parameters[1])
      goto Usage; /* more than one filename specified */

    if (!(file = fopen(*parameters, "wb"))) {
      fprintf (stderr, "%s: Could not open the file `%s'.\n", myname,
		       *parameters);
      prclose ();
      return 5;
    }
  }

  wait_output (REQ_INFO); /* request machine info */

  fprintf (stderr, "%s: machine type %u.\n", myname, wait_input ());

  driveraddr = wait_input();
  driveraddr |= wait_input() << 8;
  basicaddr = wait_input();
  basicaddr |= wait_input() << 8;

  fprintf (stderr, "%s: Driver address %04X, BASIC start address %04X.\n",
		   myname, driveraddr, basicaddr);

  if ((length = prsave(bank, start, end, buffer, 1)) >= 0) {
    fputc (start, file);
    fputc (start >> 8, file);
    fwrite (buffer, 1, length, file);
  }

  prclose ();

  return 0;
}

unsigned
prsave(int bank, int start, int end, unsigned char *buffer, int verbose)
{
  unsigned length;

  output (REQ_SAVE); /* op code for download */
  output ((unsigned char)bank); /* bank address */

  if (wait_input ()) {
    if (verbose)
      fprintf (stderr, "%s: not ready to transfer\n", myname);
    return 0;
  }
  else if (verbose)
    fprintf (stderr, "%s: ok to transfer\n", myname);

  output ((unsigned char)start);
  output ((unsigned char)(start >> 8));
  output ((unsigned char)end);
  output ((unsigned char)(end >> 8));

  length = (end - start) & 65535;

  if (!length) length = 65536;

  receive (buffer, length);

  return length;
}
