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

#include "prtrans.h"

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

#if defined(__MAIN_C__)
unsigned char buffer[256];
#else
extern unsigned char buffer[];
#endif

int main(int argc, char **argv);

void
printdir(unsigned char *p, int length, FILE *file)
{
  /*
   * State: 0,1: ignore load address
   *	    2,3: line link
   *	    4,5: line number
   *	    6  : line contents
   *	    7  : end
   */
  static int state = 0;
  static int lineno;

  while (length > 0) {
    switch(state) {
    case 0:
    case 1:
      state++;
      break;
    case 2:	/* ignore low byte of link */
      state++;
      break;
    case 3:
      state++;
      if (*p == 0) {
	state = 7;
      }
      break;
    case 4:
      state++;
      lineno = *p;
      break;
    case 5:
      state++;
      lineno += 256 * *p;
      fprintf(file, " %d ", lineno);
      break;
    case 6:
      if (*p == 0) {
	state = 2;
	putc('\n', file);
      } else {
	static char tmp[2];
	tmp[0] = *p;
	petscii2ascii(tmp);
	putc(tmp[0], file);
      }
      break;
    }
    length--;
    p++;
  }
}

int
main(int argc, char **argv)
{
  FILE *file = stdout;
  int device = 8;
  int byte;
  char **parameters = argv;
  char *remotefile;
  char *localfile;
  char *portspecified = NULL;
  char *prg = "prrfile.prg"; /* loader program file name */
  int specified_localfile = 0;
  baseaddr = portaddr[DEFAULT_PORT];

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

    switch (parameters[0][1]) {
    case 'd':
      device = strtoul (*++parameters, NULL, 0);

      if (device > 15) {
	fprintf (stderr, "%s: Illegal device number specified.\n", *argv);
	return 1;
      }

      break;

    case 'l':
      prg = *++parameters;
      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",
			 *argv);
	return 1;
      }

      portspecified = *parameters;
      baseaddr = portaddr[baseaddr];
      break;

    case '?':
    case 'h':
    Usage:
      fprintf (stderr, "%s: Dumps a file accessible from a remote "
		       "computer to a file.\n\n", *argv);
      fprintf (stderr, "Usage: %s [options] filename [local filename]\n",
		       *argv);
      fprintf (stderr, "Options:\n\t"
			 "-d device\t"
			     "Specify the device number (0-15)\n\t"
			 "-l filename\t"
			     "Specify the filename of the client program\n\t"
			 "-p port\t"
			     "Specify the printer port (0 to 3)\n");
      fprintf (stderr, "The filename can start with a $, in which case it is\n"
		       "printed as a directory, unless a local name is given.\n"
		       "The remote filename is converted to PETSCII.\n"
		       "The default local file name has / characters converted to -.\n");

      return 1;

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

  if (!*parameters) goto Usage;

  localfile = *parameters++;
  remotefile = strdup(localfile);
  ascii2petscii(remotefile);
  {
    char *bad;
    while ((bad = strpbrk(localfile, "/")) != NULL)
      *bad = '-';
  }

  if (*parameters) {
    localfile = *parameters++;
    specified_localfile = 1;
  }

  if (!specified_localfile && localfile[1] == ':') {
    localfile += 2;
  }
  if (remotefile[0] == '$' && !specified_localfile) {
    file = stdout;
    localfile = "$";
  } else if (strcmp(localfile, "-") == 0) {
    file = stdout;
  } else if (!(file = fopen(localfile, "wb"))) {
    fprintf (stderr, "%s: Could not open the file `%s'.\n", *argv,
		       localfile);
    return 1;
  }

  {
    int addr;

    FILE *f = fopen(prg, "r");
    if (f == NULL) {
      fprintf(stderr, "%s: Cannot find %s to download\n", *argv, prg);
      return 1;
    }

    addr = fgetc(f);
    addr |= fgetc(f) << 8;
    fclose(f);

#if defined(__MAIN_C__)
    {
      char cmd[80];
      sprintf(cmd, "prload -j %x ", addr);

      if (portspecified) {
        strcat (cmd, "-p ");
        strcat (cmd, portspecified);
        strcat (cmd, " ");
      }

      strcat (cmd, prg);
  
      fprintf(stderr, "%s\n", cmd);
      system(cmd);
    }
#else
    {
      char saddr[10];
      sprintf (saddr, "%x", addr);
      vmain (main_prload, 4, "prload", "-j", saddr,
             portspecified ? "-p", portspecified, prg, NULL : prg, NULL);
    }
#endif
  }

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

  if (wait_input ()) {
    fprintf (stderr, "%s: not ready to transfer\n", *argv);
    return 6;
  }
  else
    fprintf (stderr, "%s: ok to transfer\n", *argv);

  byte = strlen(remotefile);
  output(byte);
  send(remotefile, byte);
  output(device);

  if ((byte = wait_input ()) != 0) {
    fprintf (stderr, "%s: file error %d\n", *argv, byte);
    return 7;
  }
  fprintf(stderr, "reading %s to %s...\n", remotefile, localfile);

  /* loop to get all file blocks */
  for (;;) {
    int length;

    for (;;) {
      int chksum;
      int i;

      length = input();
      if (length == 0)
	break;	      /* end of file */

      receive(buffer, length + 1);

      chksum = 0;
      for (i = 0; i < length; i++) {
	chksum += buffer[1 + i];
      }

      if ((chksum & 0xFF) == buffer[0]) {
	output(0x80);
	break;
      }
      fprintf(stderr, "checksum error "
		      "(received %02x, calculated %02x), retrying\n",
		      buffer[0], (chksum & 0xFF));
      output(0x81);
    }
    if (length == 0)
      break;
    if (localfile[0] == '$') {
      printdir(buffer + 1, length, file);
    } else {
      fwrite (buffer + 1, 1, length, file);
    }
  }

  fclose(file);

  output(0);	/* terminate remote side */

  prclose ();

  return 0;
}
