/*
** FILE:	idev.c
** PROGRAM:	idev
** VERSION:	1.0
**
** DESCRIPTIPON:
**	This file contains the function idev() and its support functions.
**	It forms the heart of the program, and is responsible for all
**	user interaction.  Idev() returns when the user asks to quit.
**
**	Idev() expects the device name, unit number and device flags
**	as supplied by the user, and also the IORequest, properly
**	initialized by OpenDevice() with the given parameters.
**
** HISTORY:
**	26-Aug-87	Original Version   (Ed Puckett)
*/

#include <exec/types.h>
#include <exec/lists.h>
#include <exec/nodes.h>
#include <exec/ports.h>
#include <exec/io.h>
#include <exec/devices.h>
#include <exec/libraries.h>
#include <libraries/dos.h>
#include <stdio.h>
#include <ctype.h>

#include "main.h"
#include "idev.h"



#define BUFSIZE 	1024

static char  buffer[BUFSIZE];



typedef enum
  { C_QUIT,
    C_HELP,
    C_RDIOREQ,
    C_WRIOREQ,
    C_RDBUFFER,
    C_WRBUFFER,
    C_PATCHBUFADDR,
    C_SEND,
    C_VECT
  }
COMMAND;



extern int  vect_intfc();	   /* assembly interface for vect() */



/*-------------------------------------------------------------------------------
*/

void  idev (devname, unitnum, ioreq, flags)

char		 *devname;
int		 unitnum;
struct IOStdReq  *ioreq;
ULONG		 flags;

{ COMMAND  cmd;
  char	   filename[257];
  int	   size, vectnum;
  int	   prot_offset;
  COMMAND  getcmd ();
  BOOL	   getstring(), getint();
  void	   help(), rdfile(), wrfile(), send(), vect();


  help (devname, unitnum, ioreq, flags);

  prot_offset= (char *) &ioreq->io_Command - (char *) ioreq;

  while ((cmd= getcmd ()) != C_QUIT)
    { switch (cmd)
	{ case C_HELP:
	    help (devname, unitnum, ioreq, flags);
	    break;

	  case C_RDIOREQ:
	    if ( getstring (filename, sizeof (filename)) )
	      rdfile (((char *) ioreq + prot_offset), (IOREQSIZE - prot_offset), filename);
	    break;

	  case C_WRIOREQ:
	    if ( getstring (filename, sizeof (filename)) && getint (&size) )
	      wrfile (((char *) ioreq + prot_offset), (IOREQSIZE - prot_offset), size, filename);
	    break;

	  case C_RDBUFFER:
	    if ( getstring (filename, sizeof (filename)) )
	      rdfile ((char *) buffer, BUFSIZE, filename);
	    break;

	  case C_WRBUFFER:
	    if ( getstring (filename, sizeof (filename)) && getint (&size) )
	      wrfile ((char *) buffer, BUFSIZE, size, filename);
	    break;

	  case C_PATCHBUFADDR:
	    ioreq->io_Data= (APTR) buffer;
	    printf ("Buffer address 0x%08lx patched to io_Data field\n", (unsigned long) buffer);
	    break;

	  case C_SEND:
	    send (ioreq);
	    break;

	  case C_VECT:
	    if ( getint (&vectnum) )
	      vect (ioreq, vectnum);
	    break;
	}
    }
}



/*-------------------------------------------------------------------------------
*/

/* Note: the CC_x defines should be lowercase characters if alphabetic */

#define CC_HELP1	'?'
#define CC_HELP2	'h'
#define CC_READ 	'r'
#define CC_WRITE	'w'
#define CCQ_IOREQ	'i'
#define CCQ_BUFFER	'b'
#define CC_PATCHBUFADDR '&'
#define CC_SEND 	'!'
#define CC_VECT 	'^'
#define CC_QUIT 	'q'



static COMMAND	getcmd ()

{ char	 cmdchar[2], qual[2];
  void	 ckbrk(), flushline();

  for (;;)
    { ckbrk ();

      printf ("\n%s--> ", cmdname);

      if (scanf ("%1s", cmdchar) == EOF)
	{ printf ("\n*** EOF\n");
	  return C_QUIT;
	}

      cmdchar[0]= tolower (cmdchar[0]);
      switch (cmdchar[0])
	{ case CC_HELP1:
	  case CC_HELP2:
	    return C_HELP;

	  case CC_READ:
	  case CC_WRITE:
	    if (scanf ("%1s", qual) == EOF)
		{ printf ("\n*** EOF\n");
		  return C_QUIT;
		}

	    qual[0]= tolower (qual[0]);
	    switch (qual[0])
	      { case CCQ_IOREQ:
		  return  ((cmdchar[0] == CC_READ) ? C_RDIOREQ : C_WRIOREQ);

		case CCQ_BUFFER:
		  return  ((cmdchar[0] == CC_READ) ? C_RDBUFFER : C_WRBUFFER);

		default:
		  printf ("\n*** Qualifier for '%c' must be '%c' or '%c'.", cmdchar[0], CCQ_IOREQ, CCQ_BUFFER);
	      }

	    break;

	  case CC_PATCHBUFADDR:
	    return C_PATCHBUFADDR;

	  case CC_SEND:
	    return C_SEND;

	  case CC_VECT:
	    return C_VECT;

	  case CC_QUIT:
	    return C_QUIT;
	}

      printf ("\n*** Invalid command -- enter '%c' or '%c' for help.\n", CC_HELP1, CC_HELP2);

      flushline ();
    }
}



static void  help (devname, unitnum, ioreq, flags)

char		 *devname;
int		 unitnum;
struct IOStdReq  *ioreq;
ULONG		 flags;

{ printf ("\n");
  printf ("Device: \"%s\"\n",  devname);
  printf ("Unit:   %d\n",      unitnum);
  printf ("Flags:  0x%08lx\n", flags);
  printf ("\n");
  printf ("Buffer Address = 0x%08lx     I/O Request Address = 0x%08lx\n", (unsigned long) buffer, (unsigned long) ioreq);
  printf ("Buffer Size    = 0x%08x     I/O Request Size    = 0x%08x\n",  (unsigned) BUFSIZE, (unsigned) IOREQSIZE);
  printf ("\n");
  printf ("Commands:\n");
  printf ("   %c or %c                  help\n",                                    CC_HELP1, CC_HELP2);
  printf ("   %c%c filename             read  I/O request from file\n",             CC_READ,  CCQ_IOREQ);
  printf ("   %c%c filename size        write I/O request to file\n",               CC_WRITE, CCQ_IOREQ);
  printf ("   %c%c filename             read  buffer from file\n",                  CC_READ,  CCQ_BUFFER);
  printf ("   %c%c filename size        write buffer to file\n",                    CC_WRITE, CCQ_BUFFER);
  printf ("   %c                       patch buffer address to ioreq->io_Data\n",   CC_PATCHBUFADDR);
  printf ("   %c                       send I/O request to device via DoIO\n",      CC_SEND);
  printf ("   %c n                     send I/O request in reg A1 via vector #n\n", CC_VECT);
  printf ("   %c                       quit\n",                                     CC_QUIT);
  printf ("\n");
  printf ("Notes:  I/O request memory is read/written starting from io_Command.\n");
  printf ("        Vectors are numbered starting from 1.\n");
  printf ("        ESC ('\\033') will abort a partially entered command.\n");
}



/*-------------------------------------------------------------------------------
*/

static BOOL  getstring (buf, bufsize)

char  *buf;
int   bufsize;

{ int	    c;
  unsigned  bufpos;
  void	    ckbrk(), flushline();


  ckbrk ();

  buf[0]= '\0';

  do
    { c= getchar ();

      if ((c == EOF) || (c == '\033'))
	{ flushline ();
	  return FALSE;
	}

      if (c == '\n')
	printf (">>> ");
    }
  while (isspace (c));

  ungetc (c, stdin);


  ckbrk ();

  for (bufpos= 0; bufpos < bufsize; ++bufpos)
    { c= getchar ();

      if ((c == EOF) || (c == '\033'))
	{ flushline();
	  buf[0]= '\0';
	  return FALSE;
	}

      if (isspace (c))
	{ buf[bufpos]= '\0';
	  return TRUE;
	}

      buf[bufpos]= c;
    }


  printf ("\n*** Input buffer overflow\n");
  flushline ();
  buf[bufsize - 1]= '\0';
  return FALSE;
}



static BOOL  getint (ip)

int  *ip;

{ char	str[20];
  BOOL	getstring();

  if (! getstring (str, sizeof (str)))
    return FALSE;

  if (sscanf (str, "%d", ip) != 1)
    { printf ("\n*** Could not scan number\n");
      return FALSE;
    }

  return TRUE;
}



static void  rdfile (buf, bufsize, filename)

char  *buf;
int   bufsize;
char  *filename;

{ FILE	*fp;
  int	n;

  if ((fp= fopen (filename, "r")) == NULL)
    { printf ("*** Can't open \"%s\"\n", filename);
      return;
    }

  n= fread ((char *) buf, 1, bufsize, fp);

  if (getc (fp) != EOF)
    printf ("*** Warning: buffer size (%d) exceeded before EOF.\n", bufsize);

  printf ("%d bytes read.\n", n);

  fclose (fp);
}



static void  wrfile (buf, bufsize, xfsize, filename)

char  *buf;
int   bufsize;
int   xfsize;
char  *filename;

{ FILE	*fp;
  int	n;

  if ((xfsize <= 0) || (xfsize > bufsize))
    { printf ("*** Size must be > 0, <= %d\n", bufsize);
      return;
    }

  if ((fp= fopen (filename, "w")) == NULL)
    { printf ("*** Can't open \"%s\"\n", filename);
      return;
    }

  if ((n= fwrite ((char *) buf, 1, xfsize, fp)) < xfsize)
    printf ("*** Warning: incomplete write.\n");

  printf ("%d bytes written.\n", n);

  fclose (fp);
}



static void  send (req)

struct IORequest  *req;

{ int  error;

  printf ("Sending I/O request...");
  error= DoIO (req);
  printf ("\nI/O request sent...");

  if (error == 0)
    printf ("no error\n");
  else
    printf ("error = %d\n", error);
}



static void  vect (req, vectnum)

struct IORequest  *req;
int		  vectnum;

{ struct Device  *dev;
  int		 vn, error;
  LONG		 val;
  int		 vect_intfc();


  if (vectnum <= 0)
    { printf ("*** Vector number must be positive\n");
      return;
    }


  dev= req->io_Device;

  for (vn= 1; vn <= vectnum; vn += 1)
    { if ( ((val= *((LONG *) ((char *) dev - (LIB_VECTSIZE * vn)))) == -1) || (val == NULL) )
	{ printf ("*** There are only %d vectors\n", (vn - 1));
	  return;
	}
    }


  printf ("Vectoring I/O request through vector #%d...", vectnum);
  error= vect_intfc (req, vectnum);
  printf ("\nI/O request vectored...");

  if (error == 0)
    printf ("no error\n");
  else
    printf ("error = %d\n", error);
}



/*-------------------------------------------------------------------------------
*/

static void  ckbrk ()

{ ULONG  SetSignal();

  if (SetSignal (0, 0) & SIGBREAKF_CTRL_C)
    { printf ("\n*** BREAK\n");
      quit (Q_ABORT, NULL, 0, 0, 0);
    }
}



static void  flushline ()

{ register int	c;
  void		ckbrk();

  ckbrk ();

  while ( ((c= getchar ()) != EOF) && (c != '\n') )
    ;
}

