diff --git a/avrprog.c b/avrprog.c
index d561100a..08e03b8f 100644
--- a/avrprog.c
+++ b/avrprog.c
@@ -63,8 +63,9 @@
 #include <stdarg.h>
 #include <sys/stat.h>
 #include </sys/dev/ppbus/ppi.h>
+#include <limits.h>
 
-#define PARALLEL "/dev/ppi0"
+#define DEFAULT_PARALLEL "/dev/ppi0"
 
 char * version = "$Id$";
 
@@ -101,21 +102,102 @@ typedef enum {
   AVR_FLASH_HI
 } AVRMEM;
 
+enum {
+  FMT_AUTO,
+  FMT_SREC,
+  FMT_IHEX,
+  FMT_RBIN
+};
 
 struct avrpart {
-  char * partdesc;
+  char * partdesc;   
   char * optiontag;
   int flash_size;
   int eeprom_size;
+  unsigned char f_readback;
+  unsigned char e_readback[2];
+  unsigned char * flash;
+  unsigned char * eeprom;
 };
 
 
 struct avrpart parts[] = {
-  { "AT90S8515", "8515", 8192, 512 },
-  { "AT90S2313", "2313", 2048, 128 },
-  { "AT90S1200", "1200", 1024,  64 }
+  { "AT90S8515", "8515", 8192, 512, 0x7f, { 0x80, 0x7f }, NULL, NULL },
+  { "AT90S2313", "2313", 2048, 128, 0x7f, { 0x80, 0x7f }, NULL, NULL },
+  { "AT90S1200", "1200", 1024,  64, 0x7f, { 0x80, 0x7f }, NULL, NULL }
 };
 
+#define N_AVRPARTS (sizeof(parts)/sizeof(struct avrpart))
+
+
+struct fioparms {
+  int    op;
+  char * mode;
+  char * iodesc;
+  char * dir;
+  char * rw;
+};
+
+enum {
+  FIO_READ,
+  FIO_WRITE
+};
+
+
+
+#define MAX_LINE_LEN 256  /* max line length for ASCII format input files */
+
+
+char * usage_text =
+"\n"
+"Usage:  avrprog [options]\n"
+"\n"
+"  Available Options:\n"
+"\n"
+"    -m MemType    : select memory type for reading or writing\n"
+"                      \"e\", \"eeprom\" = EEPROM\n"
+"                      \"f\", \"flash\"  = FLASH\n"
+"\n"
+"    -i Filename   : select input file\n"
+"\n"
+"    -o Filename   : select output file, \"-\" = stdout\n"
+"\n"
+"    -f Format     : select input / output file format\n"
+"                      \"i\" = Intel Hex\n"
+"                      \"s\" = Motorola S-Record\n"
+"                      \"r\" = Raw binary\n"
+"                      \"a\" = Auto detect (valid input only)\n"
+"\n"
+"    -p Part       : select Atmel part number (see below for valid parts)\n"
+"\n"
+"    -P Parallel   : select parallel port device name (default = /dev/ppi0)\n"
+"\n"
+"    -s            : read device signature bytes\n"
+"\n"
+"    -F            : override invalid device signature check\n"
+"\n"
+"    -c            : enter interactive command mode (or read commands\n"
+"                    from stdin)\n"
+"\n"
+"    -e            : perform a chip erase (required before programming)\n"
+"\n";
+
+
+
+int list_valid_parts ( FILE * f, char * prefix )
+{
+  int i;
+
+  for (i=0; i<N_AVRPARTS; i++) {
+    fprintf(f, "%s\"%s\" = %s\n", 
+            prefix, parts[i].optiontag, parts[i].partdesc);
+  }
+
+  return i;
+}
+
+
+
 
 /*
  * set 'get' and 'set' appropriately for subsequent passage to ioctl()
@@ -323,10 +405,10 @@ unsigned char avr_read_byte ( int fd, AVRMEM memtype, unsigned short addr )
       break;
     case AVR_EEPROM: 
       cmd[0] = 0xa0;
-      /* addr &= 0x7f; */
       break;
     default:
-      fprintf(stderr, "%s: avr_read_byte(); internal error: invalid memtype=%d\n",
+      fprintf(stderr, 
+              "%s: avr_read_byte(); internal error: invalid memtype=%d\n",
               progname, memtype);
       exit(1);
       break;
@@ -343,23 +425,31 @@ unsigned char avr_read_byte ( int fd, AVRMEM memtype, unsigned short addr )
 
 
 /*
- * read 'n' words of data from the indicated memory region.  If the
- * flash memory is being read, n*2 bytes will be read into 'buf'; if
- * the eeprom is being read, 'n' bytes will be read into 'buf'.
+ * read the entirety of the specified memory type into the
+ * corresponding buffer of the avrpart pointed to by 'p'.  
  */
-int avr_read ( int fd, AVRMEM memtype, unsigned start, unsigned n, 
-               unsigned char * buf, int bufsize )
+int avr_read ( int fd, AVRMEM memtype, struct avrpart * p )
 {
   unsigned char rbyte, memt;
-  unsigned short end, i, bi;
+  unsigned short n, start, end, i, bi;
+  unsigned char * buf;
+  int bufsize;
 
   switch (memtype) {
     case AVR_FLASH  :
-      memt = AVR_FLASH_LO;
+      memt    = AVR_FLASH_LO;
+      buf     = p->flash;
+      n       = p->flash_size/2;
+      bufsize = p->flash_size;
       break;
+
     case AVR_EEPROM : 
-      memt = memtype;
+      memt    = memtype;
+      buf     = p->eeprom;
+      n       = p->eeprom_size;
+      bufsize = p->eeprom_size;
       break;
+
     default:
       fprintf(stderr, "%s: avr_read(); internal error: invalid memtype=%d\n",
               progname, memtype);
@@ -398,7 +488,8 @@ int avr_read ( int fd, AVRMEM memtype, unsigned start, unsigned n,
 /*
  * write a byte of data to the indicated memory region
  */
-int avr_write_byte ( int fd, AVRMEM memtype, unsigned short addr, unsigned char data )
+int avr_write_byte ( int fd, AVRMEM memtype, 
+                     unsigned short addr, unsigned char data )
 {
   unsigned char cmd[4], res[4];
   unsigned char r;
@@ -414,10 +505,10 @@ int avr_write_byte ( int fd, AVRMEM memtype, unsigned short addr, unsigned char
       break;
     case AVR_EEPROM: 
       cmd[0] = 0xc0;
-      /* addr &= 0x7f; */
       break;
     default:
-      fprintf(stderr, "%s: avr_write_byte(); internal error: invalid memtype=%d\n",
+      fprintf(stderr,
+              "%s: avr_write_byte(); internal error: invalid memtype=%d\n",
               progname, memtype);
       exit(1);
       break;
@@ -457,24 +548,35 @@ int avr_write_byte ( int fd, AVRMEM memtype, unsigned short addr, unsigned char
 
 
 /*
- * write 'bufsize' bytes of data to the indicated memory region.
+ * Write the whole memory region (flash or eeprom, specified by
+ * 'memtype') from the corresponding buffer of the avrpart pointed to
+ * by 'p'.  All of the memory is updated, however, input data of 0xff
+ * is not actually written out, because empty flash and eeprom
+ * contains 0xff, and you can't actually write 1's, only 0's.
  */
-int avr_write ( int fd, AVRMEM memtype, unsigned start, 
-                unsigned char * buf, int bufsize )
+int avr_write ( int fd, AVRMEM memtype, struct avrpart * p )
 {
   unsigned char data, memt;
-  unsigned short end, i, bi;
+  unsigned short start, end, i, bi;
   int nl;
   int rc;
+  unsigned char * buf;
+  int bufsize;
+
+  start = 0;
 
   switch (memtype) {
     case AVR_FLASH  : 
-      end = start+bufsize/2;
-      memt = AVR_FLASH_LO;
+      buf     = p->flash;
+      bufsize = p->flash_size;
+      end     = start+bufsize/2;
+      memt    = AVR_FLASH_LO;
       break;
     case AVR_EEPROM : 
-      end = start+bufsize;
-      memt = memtype;
+      buf     = p->eeprom;
+      bufsize = p->eeprom_size;
+      end     = start+bufsize;
+      memt    = memtype;
       break;
     default:
       fprintf(stderr, "%s: avr_write(); internal error: invalid memtype=%d\n",
@@ -489,7 +591,10 @@ int avr_write ( int fd, AVRMEM memtype, unsigned start,
     /* eeprom or low byte of flash */
     data = buf[bi++];
     nl = 0;
-    rc = avr_write_byte(fd, memt, i, data );
+    if (data != 0xff)
+      rc = avr_write_byte(fd, memt, i, data );
+    else
+      rc = 0;
     fprintf(stderr, "                      \r%4u 0x%02x", i, data);
     if (rc) {
       fprintf(stderr, " ***failed;  ");
@@ -499,7 +604,10 @@ int avr_write ( int fd, AVRMEM memtype, unsigned start,
     if (memtype == AVR_FLASH) {
       /* high byte of flash */
       data = buf[bi++];
-      rc = avr_write_byte(fd, AVR_FLASH_HI, i, data );
+      if (data != 0xff)
+        rc = avr_write_byte(fd, AVR_FLASH_HI, i, data );
+      else
+        rc = 0;
       fprintf(stderr, " 0x%02x", data);
       if (rc) {
         fprintf(stderr, " ***failed;  " );
@@ -666,64 +774,396 @@ int ppi_sense_test ( int fd )
  */
 void usage ( void )
 {
-  int i;
 
-  fprintf ( stderr, 
-            "\nUsage:  %s [options]\n"
-            "\n"
-            "  Available Options:\n"
-            "    -r            : erase the flash and eeprom (required before programming)\n"
-            "    -e            : select eeprom for reading or writing\n"
-            "    -f            : select flash for reading or writing\n"
-            "    -p Part       : see below for valid parts\n"
-            "    -u InputFile  : write data from this file\n"
-            "    -o OutputFile : write data to this file\n"
-            "    -F            : override invalid device signature check\n"
-            "    -s            : read device signature bytes\n"
-            "\n",
-            progname );
+  fprintf ( stderr, "%s", usage_text );
 
   fprintf(stderr, "  Valid Parts for the -p option are:\n");
-  for (i=0; i<sizeof(parts)/sizeof(parts[0]); i++) {
-    fprintf(stderr, "    \"%s\" = %s\n", 
-            parts[i].optiontag, parts[i].partdesc);
-  }
+  list_valid_parts(stderr, "    ");
   fprintf(stderr, "\n");
 
 }
 
 
+
+int b2ihex ( unsigned char * inbuf, int bufsize, 
+             int recsize, int startaddr,
+             char * outfile, FILE * outf )
+{
+  unsigned char * buf;
+  unsigned int nextaddr;
+  int n;
+  int i;
+  unsigned char cksum;
+
+  if (recsize > 255) {
+    fprintf ( stderr, "%s: recsize=%d, must be < 256\n",
+              progname, recsize );
+    return -1;
+  }
+
+  nextaddr = startaddr;
+
+  buf = inbuf;
+  while (bufsize) {
+    n = recsize;
+    if (n > bufsize)
+      n = bufsize;
+
+    if (n) {
+      cksum = 0;
+      fprintf ( outf, ":%02X%04X00", n, nextaddr );
+      cksum += n + ((nextaddr >> 8) & 0x0ff) + (nextaddr & 0x0ff);
+      for (i=0; i<n; i++) {
+        fprintf ( outf, "%02X", buf[i] );
+        cksum += buf[i];
+      }
+      cksum = -cksum;
+      fprintf ( outf, "%02X\n", cksum );
+      
+      nextaddr += n;
+    }
+
+    /* advance to next 'recsize' bytes */
+    buf += n;
+    bufsize -= n;
+  }
+
+  /*-----------------------------------------------------------------
+    add the trailing zero data line
+    -----------------------------------------------------------------*/
+  cksum = 0;
+  n = 0;
+  fprintf ( outf, ":%02X%04X00", n, nextaddr );
+  cksum += n + ((nextaddr >> 8) & 0x0ff) + (nextaddr & 0x0ff);
+  cksum = -cksum;
+  fprintf ( outf, "%02X\n", cksum );
+
+  return 0;
+}
+
+
+int ihex2b ( char * infile, FILE * inf,
+             unsigned char * outbuf, int bufsize )
+{
+  unsigned char buffer [ MAX_LINE_LEN ];
+  unsigned char * buf;
+  unsigned int prevaddr, nextaddr;
+  unsigned int b;
+  int n;
+  int i, j;
+  unsigned int cksum, rectype;
+  int lineno;
+
+  lineno   = 0;
+  prevaddr = 0;
+  buf      = outbuf;
+
+  while (fgets((char *)buffer,MAX_LINE_LEN,inf)!=NULL) {
+    lineno++;
+    if (buffer[0] != ':')
+      continue;
+    if (sscanf((char *)&buffer[1], 
+               "%02x%04x%02x", &n, &nextaddr, &rectype) != 3) {
+      fprintf(stderr, "%s: invalid record at line %d of \"%s\"\n",
+              progname, lineno, infile);
+      exit(1);
+    }
+
+    if (rectype != 0) {
+      fprintf(stderr, 
+              "%s: don't know how to deal with rectype=%d " 
+              "at line %d of \"%s\"\n",
+              progname, rectype, lineno, infile);
+      exit(1);
+    }
+
+    if (n && ((nextaddr + n) > bufsize)) {
+      fprintf(stderr, "%s: address 0x%04x out of range at line %d of %s\n",
+              progname, nextaddr+n, lineno, infile);
+      return -1;
+    }
+
+    /* start computing a checksum */
+    cksum = n + ((nextaddr >> 8 ) & 0x0ff) + (nextaddr & 0x0ff);
+
+    for (i=0; i<n; i++) {
+      if (sscanf((char *)&buffer[i*2+9], "%02x", &b) != 1) {
+        fprintf(stderr, "%s: can't scan byte number %d at line %d of %s\n",
+                progname, i, lineno, infile);
+        /* display the buffer and the position of the scan error */
+        fprintf(stderr, "%s", buffer);
+        for (j=0; j<9+2*i; j++) {
+          fprintf(stderr, " ");
+        }
+        fprintf(stderr, "^\n");
+        return -1;
+      }
+
+      buf[nextaddr + i] = b;
+      cksum += b;
+    }
+
+    /*-----------------------------------------------------------------
+      read the cksum value from the record and compare it with our
+      computed value
+      -----------------------------------------------------------------*/
+    if (sscanf((char *)&buffer[n*2+9], "%02x", &b) != 1) {
+      fprintf(stderr, "%s: can't scan byte number %d at line %d of %s\n",
+              progname, i, lineno, infile);
+      /* display the buffer and the position of the scan error */
+      fprintf(stderr, "%s", buffer);
+      for (j=0; j<9+2*i; j++) {
+        fprintf(stderr, " ");
+      }
+      fprintf(stderr, "^\n");
+      return -1;
+    }
+
+    cksum = -cksum & 0xff;
+    if (cksum != b) {
+      fprintf(stderr, 
+              "%s: cksum error for line %d of \"%s\": computed=%02x "
+              "found=%02x\n",
+              progname, lineno, infile, cksum, b);
+      return -1;
+    }
+
+    prevaddr = nextaddr + n;
+  }
+
+  return 0;
+}
+
+
+
+int fileio_rbin ( struct fioparms * fio,
+                  char * filename, FILE * f, unsigned char * buf, int size )
+{
+  int rc;
+
+  switch (fio->op) {
+    case FIO_READ:
+      rc = fread(buf, 1, size, f);
+      break;
+    case FIO_WRITE:
+      rc = fwrite(buf, 1, size, f);
+      break;
+  }
+
+  if (rc < size) {
+    fprintf(stderr, 
+            "%s: %s error %s %s: %s; %s %d of the expected %d bytes\n", 
+            progname, fio->iodesc, fio->dir, filename, strerror(errno),
+            fio->rw, rc, size);
+    return -5;
+  }
+
+  return rc;
+}
+
+
+int fileio_ihex ( struct fioparms * fio, 
+                  char * filename, FILE * f, unsigned char * buf, int size )
+{
+  int rc;
+
+  switch (fio->op) {
+    case FIO_WRITE:
+      rc = b2ihex(buf, size, 32, 0, filename, f);
+      if (rc) {
+        return -5;
+      }
+      break;
+
+    case FIO_READ:
+      rc = ihex2b(filename, f, buf, size);
+      if (rc)
+        return -5;
+      break;
+
+    default:
+      fprintf(stderr, "%s: invalid Intex Hex file I/O operation=%d\n",
+              progname, fio->op);
+      return -5;
+      break;
+  }
+
+  return 0;
+}
+
+
+int fileio_srec ( struct fioparms * fio,
+                  char * filename, FILE * f, unsigned char * buf, int size )
+{
+  fprintf(stderr, "%s: Motorola S-Record %s format not yet supported\n",
+          progname, fio->iodesc);
+  return -5;
+}
+
+
+int fileio_setparms ( int op, struct fioparms * fp )
+{
+  fp->op = op;
+
+  switch (op) {
+    case FIO_READ:
+      fp->mode   = "r";
+      fp->iodesc = "input";
+      fp->dir    = "from";
+      fp->rw     = "read";
+      break;
+
+    case FIO_WRITE:
+      fp->mode   = "w";
+      fp->iodesc = "output";
+      fp->dir    = "to";
+      fp->rw     = "wrote";
+      break;
+
+    default:
+      fprintf(stderr, "%s: invalid I/O operation %d\n",
+              progname, op);
+      return -1;
+      break;
+  }
+
+  return 0;
+}
+
+
+int fileio ( int op, char * filename, int format, 
+             struct avrpart * p, AVRMEM memtype )
+{
+  int rc;
+  FILE * f;
+  char * fname;
+  unsigned char * buf;
+  int size;
+  struct fioparms fio;
+  int i;
+
+  rc = fileio_setparms(op, &fio);
+  if (rc < 0)
+    return -1;
+
+  if (strcmp(filename, "-")==0) {
+    if (fio.op == FIO_READ) {
+      fname = "<stdin>";
+      f = stdin;
+    }
+    else {
+      fname = "<stdout>";
+      f = stdout;
+    }
+  }
+  else {
+    f = fopen(filename, fio.mode);
+    if (f == NULL) {
+      fprintf(stderr, "%s: can't open %s file %s: %s\n",
+              progname, fio.iodesc, filename, strerror(errno));
+      return -2;
+    }
+  }
+
+  switch (memtype) {
+    case AVR_EEPROM:
+      buf = p->eeprom;
+      size = p->eeprom_size;
+      break;
+
+    case AVR_FLASH:
+      buf = p->flash;
+      size = p->flash_size;
+      break;
+      
+    default:
+      fprintf(stderr, "%s: invalid memory type for %s: %d\n",
+              progname, fio.iodesc, memtype);
+      return -3;
+  }
+
+  if (fio.op == FIO_READ) {
+    /* 0xff fill unspecified memory */
+    for (i=0; i<size; i++) {
+      buf[i] = 0xff;
+    }
+  }
+
+  switch (format) {
+    case FMT_IHEX:
+      rc = fileio_ihex(&fio, fname, f, buf, size);
+      break;
+
+    case FMT_SREC:
+      rc = fileio_srec(&fio, fname, f, buf, size);
+      break;
+
+    case FMT_RBIN:
+      rc = fileio_rbin(&fio, fname, f, buf, size);
+      break;
+
+    default:
+      fprintf(stderr, "%s: invalid %s file format: %d\n",
+              progname, fio.iodesc, format);
+      return -4;
+  }
+
+  return rc;
+}
+
+
+char * memtypestr ( AVRMEM memtype )
+{
+  switch (memtype) {
+    case AVR_EEPROM : return "eeprom"; break;
+    case AVR_FLASH  : return "flash"; break;
+    default         : return "unknown-memtype"; break;
+  }
+}
+
+
 /*
  * main routine
  */
 int main ( int argc, char * argv [] )
 {
-  int fd;
-  int rc, exitrc;
-  int i;
-  unsigned char * buf;
-  int ch;
-  int iofd;
-  int flash, eeprom, doread, erase, dosig;
-  int size;
-  char * outputf;
-  char * inputf;
-  char * p1, * p2;
-  struct avrpart * p;
-  unsigned char sig[4], nulldev[4];
-  int len;
-  int ovsigck;
+  int              fd;          /* file descriptor for parallel port */
+  int              rc;          /* general return code checking */
+  int              exitrc;      /* exit code for main() */
+  int              i;           /* general loop counter */
+  int              ch;          /* options flag */
+  int              size;        /* size of memory region */
+  int              len;         /* length for various strings */
+  char             buf[PATH_MAX]; /* temporary buffer */
+  char           * p1;          /* used to parse CVS Id */
+  char           * p2;          /* used to parse CVS Ed */
+  unsigned char    sig[4];      /* AVR signature bytes */
+  unsigned char    nulldev[4];  /* 0xff signature bytes for comparison */
+  struct avrpart * p;           /* which avr part we are programming */
+  int              readorwrite; /* true if a chip read/write op was selected */
 
-  iofd    = -1;
-  outputf = NULL;
-  inputf  = NULL;
-  doread  = 1;
-  eeprom  = 0;
-  flash   = 0;
-  erase   = 0;
-  dosig   = 0;
-  p       = NULL;
-  ovsigck = 0;
+  /* options / operating mode variables */
+  int    memtype;     /* AVR_FLASH or AVR_EEPROM */
+  int    doread;      /* 0=reading, 1=writing */
+  int    erase;       /* 1=erase chip, 0=don't */
+  char * outputf;     /* output file name */
+  char * inputf;      /* input file name */
+  int    ovsigck;     /* 1=override sig check, 0=don't */
+  char * parallel;    /* parallel port device */
+  int    interactive; /* 1=enter interactive command mode, 0=don't */
+  int    filefmt;     /* FMT_AUTO, FMT_IHEX, FMT_SREC, FMT_RBIN */
+
+  readorwrite = 0;
+  parallel    = DEFAULT_PARALLEL;
+  outputf     = NULL;
+  inputf      = NULL;
+  doread      = 1;
+  memtype     = AVR_FLASH;
+  erase       = 0;
+  p           = NULL;
+  ovsigck     = 0;
+  interactive = 0;
+  filefmt     = FMT_AUTO;
 
   progname = rindex(argv[0],'/');
   if (progname)
@@ -731,7 +1171,6 @@ int main ( int argc, char * argv [] )
   else
     progname = argv[0];
 
-
   /*
    * Print out an identifying string so folks can tell what version
    * they are running
@@ -767,94 +1206,119 @@ int main ( int argc, char * argv [] )
   /*
    * process command line arguments
    */
-  while ((ch = getopt(argc,argv,"?efFo:p:rsu:")) != -1) {
+  while ((ch = getopt(argc,argv,"?cef:Fi:m:o:p:P:s")) != -1) {
+
     switch (ch) {
-      case 'e': /* select eeprom memory */
-        if (flash) {
-          fprintf(stderr,"%s: -e and -f are incompatible\n", progname);
-          return 1;
+      case 'm': /* select memory type to operate on */
+        if ((strcasecmp(optarg,"e")==0)||(strcasecmp(optarg,"eeprom")==0)) {
+          memtype = AVR_EEPROM;
         }
-        eeprom = 1;
-        break;
-      case 'f': /* select flash memory */
-        if (eeprom) {
-          fprintf(stderr,"%s: -e and -f are incompatible\n", progname);
-          return 1;
+        else if ((strcasecmp(optarg,"f")==0)||
+                 (strcasecmp(optarg,"flash")==0)) {
+          memtype = AVR_FLASH;
         }
-        flash = 1;
+        else {
+          fprintf(stderr, "%s: invalid memory type \"%s\"\n", 
+                  progname, optarg);
+          usage();
+          exit(1);
+        }
+        readorwrite = 1;
         break;
+
       case 'F': /* override invalid signature check */
         ovsigck = 1;
         break;
+
       case 'o': /* specify output file */
         if (inputf) {
-          fprintf(stderr,"%s: -o and -u are incompatible\n", progname);
+          fprintf(stderr,"%s: -i and -o are incompatible\n", progname);
           return 1;
         }
         doread = 1;
         outputf = optarg;
-        if (strcmp(outputf,"-")==0) {
-          iofd = fileno(stdout);
-        }
-        else {
-          iofd = open ( outputf, O_WRONLY|O_CREAT|O_TRUNC,
-                        S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
-          if (iofd < 0) {
-            fprintf(stderr, "%s: can't open output file \"%s\": %s\n",
-                    progname, outputf, strerror(errno));
-            return 1;
-          }
-        }
+        if (filefmt == FMT_AUTO)
+          filefmt = FMT_IHEX;
         break;
+
       case 'p' : /* specify AVR part */
         p = NULL;
-        for (i=0; i<sizeof(parts)/sizeof(parts[0]); i++) {
+        for (i=0; i<N_AVRPARTS; i++) {
           if (strcmp(parts[i].optiontag, optarg)==0) {
             p = &parts[i];
             break;
           }
         }
         if (p == NULL) {
-          fprintf(stderr, "%s: AVR Part \"%s\" not found.  Valid parts are:\n\n",
+          fprintf(stderr, 
+                  "%s: AVR Part \"%s\" not found.  Valid parts are:\n\n",
                   progname, optarg );
-          for (i=0; i<sizeof(parts)/sizeof(parts[0]); i++) {
-            fprintf(stderr, "    \"%s\" = %s\n", 
-                    parts[i].optiontag, parts[i].partdesc);
-          }
+          list_valid_parts(stderr,"    ");
           fprintf(stderr, "\n");
           return 1;
         }
         break;
-      case 'r': /* perform a chip erase */
+
+      case 'e': /* perform a chip erase */
         erase = 1;
         break;
-      case 's': /* read out the signature bytes */
-        dosig = 1;
-        break;
-      case 'u': /* specify input (upload) file */
+
+      case 'i': /* specify input file */
         if (outputf) {
-          fprintf(stderr,"%s: -o and -u are incompatible\n", progname);
+          fprintf(stderr,"%s: -o and -i are incompatible\n", progname);
           return 1;
         }
         doread = 0;
         inputf = optarg;
-        iofd = open ( inputf, O_RDONLY, 0);
-        if (iofd < 0) {
-          fprintf(stderr, "%s: can't open input file \"%s\": %s\n",
-                  progname, inputf, strerror(errno));
-          return 1;
+        break;
+
+      case 'f':   /* specify file format */
+        if (strlen(optarg) != 1) {
+          fprintf(stderr, "%s: invalid file format \"%s\"\n",
+                  progname, optarg);
+          usage();
+          exit(1);
+        }
+        switch (optarg[0]) {
+          case 'a' : filefmt = FMT_AUTO; break;
+          case 'i' : filefmt = FMT_IHEX; break;
+          case 'r' : filefmt = FMT_RBIN; break;
+          case 's' :
+            fprintf(stderr, "%s: Motorola S-Record format not yet supported\n",
+                    progname);
+            exit(1);
+            break;
+          default :
+            fprintf(stderr, "%s: invalid file format \"%s\"\n",
+                    progname, optarg);
+            usage();
+            exit(1);
         }
         break;
+
+      case 'c': /* enter interactive command mode */
+        if (!((inputf == NULL)||(outputf == NULL))) {
+          fprintf(stderr, 
+                  "%s: interactive mode is not compatible with -i or -o\n",
+                  progname);
+          usage();
+          exit(1);
+        }
+        interactive = 1;
+        break;
+
       case '?': /* help */
         usage();
-        return 1;
+        exit(0);
         break;
+
       default:
         fprintf(stderr, "%s: invalid option -%c\n", progname, ch);
         usage();
-        return 1;
+        exit(1);
         break;
     }
+
   }
 
   if (p == NULL) {
@@ -862,10 +1326,7 @@ int main ( int argc, char * argv [] )
             "%s: No AVR part has been specified, use \"-p Part\"\n\n"
             "  Valid Parts are:\n\n",
             progname );
-    for (i=0; i<sizeof(parts)/sizeof(parts[0]); i++) {
-      fprintf(stderr, "    \"%s\" = %s\n", 
-              parts[i].optiontag, parts[i].partdesc);
-    }
+    list_valid_parts(stderr, "    ");
     fprintf(stderr,"\n");
     return 1;
   }
@@ -874,27 +1335,27 @@ int main ( int argc, char * argv [] )
           progname, p->partdesc, p->flash_size, p->eeprom_size);
   fprintf(stderr, "\n");
 
-  if (p->flash_size >= p->eeprom_size)
-    size = p->flash_size;
-  else
-    size = p->eeprom_size;
-
-  buf = (unsigned char *) malloc(size);
-  if (buf == NULL) {
-    fprintf(stderr, 
-            "%s: out of memory allocating %d bytes for on-chip memory buffer\n",
-            progname, size);
-    return 1;
+  p->flash = (unsigned char *) malloc(p->flash_size);
+  if (p->flash == NULL) {
+    fprintf(stderr, "%s: can't alloc buffer for flash size of %d bytes\n",
+            progname, p->flash_size);
+    exit(1);
   }
 
+  p->eeprom = (unsigned char *) malloc(p->eeprom_size);
+  if (p->eeprom == NULL) {
+    fprintf(stderr, "%s: can't alloc buffer for eeprom size of %d bytes\n",
+            progname, p->eeprom_size);
+    exit(1);
+  }
 
   /*
    * open the parallel port
    */
-  fd = open ( PARALLEL, O_RDWR );
+  fd = open ( DEFAULT_PARALLEL, O_RDWR );
   if (fd < 0) {
     fprintf ( stderr, "%s: can't open device \"%s\": %s\n",
-              progname, PARALLEL, strerror(errno) );
+              progname, DEFAULT_PARALLEL, strerror(errno) );
     return 1;
   }
 
@@ -911,7 +1372,8 @@ int main ( int argc, char * argv [] )
     goto main_exit;
   }
 
-  fprintf ( stderr, "%s: AVR device initialized and ready to accept instructions\n",
+  fprintf ( stderr, 
+            "%s: AVR device initialized and ready to accept instructions\n",
             progname );
 
   /*
@@ -957,44 +1419,18 @@ int main ( int argc, char * argv [] )
   }
 
 
-  if (dosig) {
-    /*
-     * read out the on-chip signature bytes
-     */
-    fprintf(stderr, "%s: reading signature bytes: ", progname );
-    avr_signature(fd, sig);
-    for (i=0; i<4; i++)
-      fprintf(stderr, "%02x", sig[i]);
-    fprintf(stderr, "\n");
-  }
-
-
-  if (iofd < 0) {
+  if ((inputf==NULL) && (outputf==NULL)) {
     /*
      * Check here to see if any other operations were selected and
      * generate an error message because if they were, we need either
      * an input or and output file, but one was not selected.
      * Otherwise, we just shut down.  
      */
-    if (eeprom||flash) {
+    if (readorwrite) {
       fprintf(stderr, "%s: you must specify an input or an output file\n",
               progname);
       exitrc = 1;
     }
-    usage();
-    goto main_exit;
-  }
-
-
-  if (!(eeprom||flash)) {
-    /*
-     * an input file or an output file was specified, but the memory
-     * type (eeprom or flash) was not specified.  
-     */
-    fprintf(stderr, 
-            "%s: please specify either the eeprom (-e) or the flash (-f) memory\n",
-            progname);
-    exitrc = 1;
     goto main_exit;
   }
 
@@ -1003,93 +1439,55 @@ int main ( int argc, char * argv [] )
     /*
      * read out the specified device memory and write it to a file 
      */
-    if (flash) {
-      size = p->flash_size;
-      fprintf ( stderr, "%s: reading flash memory:\n", progname );
-      rc = avr_read ( fd, AVR_FLASH, 0, size/2, buf, size );
-      if (rc) {
-        fprintf ( stderr, "%s: failed to read all of flash memory, rc=%d\n", 
-                  progname, rc );
-        exitrc = 1;
-        goto main_exit;
-      }
-    }
-    else if (eeprom) {
-      size = p->eeprom_size;
-      fprintf ( stderr, "%s: reading eeprom memory:\n", progname );
-      rc = avr_read ( fd, AVR_EEPROM, 0, size, buf, size );
-      if (rc) {
-        fprintf ( stderr, "%s: failed to read all of eeprom memory, rc=%d\n", 
-                  progname, rc );
-        exitrc = 1;
-        goto main_exit;
-      }
+    fprintf ( stderr, "%s: reading %s memory:\n", 
+              progname, memtypestr(memtype) );
+    rc = avr_read ( fd, memtype, p );
+    if (rc) {
+      fprintf ( stderr, "%s: failed to read all of %s memory, rc=%d\n", 
+                progname, memtypestr(memtype), rc );
+      exitrc = 1;
+      goto main_exit;
     }
 
-    /*
-     * write it out to the specified file
-     */
-    rc = write ( iofd, buf, size );
+    rc = fileio(FIO_WRITE, outputf, filefmt, p, memtype);
     if (rc < 0) {
-      fprintf(stderr, "%s: write error: %s\n", progname, strerror(errno));
-      exitrc = 1;
-      goto main_exit;
-    }
-    else if (rc != size) {
-      fprintf(stderr, "%s: wrote only %d bytes of the expected %d\n", 
-              progname, rc, size);
+      fprintf(stderr, "%s: terminating\n", progname);
       exitrc = 1;
       goto main_exit;
     }
+
   }
   else {
     /*
-     * write the selected device memory using data from a file
+     * write the selected device memory using data from a file; first
+     * read the data from the specified file
      */
-    if (flash) {
-      size = p->flash_size;
-    }
-    else if (eeprom) {
-      size = p->eeprom_size;
-    }
-
-    /*
-     * read in the data file that will be used to write into the chip
-     */
-    rc = read(iofd, buf, size);
+    rc = fileio(FIO_READ, inputf, filefmt, p, memtype );
     if (rc < 0) {
-      fprintf(stderr, "%s: read error from \"%s\": %s\n", 
-              progname, inputf, strerror(errno));
+      fprintf(stderr, "%s: terminating\n", progname);
       exitrc = 1;
       goto main_exit;
     }
-
     size = rc;
 
     /*
      * write the buffer contents to the selected memory type
      */
-    if (flash) {
-      fprintf(stderr, "%s: writing %d bytes into flash memory:\n", 
-              progname, size);
-      rc = avr_write ( fd, AVR_FLASH, 0, buf, size );
-      if (rc) {
-        fprintf ( stderr, "%s: failed to write flash memory, rc=%d\n", 
-                  progname, rc );
-        exitrc = 1;
-        goto main_exit;
-      }
-    }
-    else if (eeprom) {
-      fprintf(stderr, "%s: writing %d bytes into eeprom memory:\n", 
-              progname, size);
-      rc = avr_write ( fd, AVR_EEPROM, 0, buf, size );
-      if (rc) {
-        fprintf ( stderr, "%s: failed to write eeprom memory, rc=%d\n", 
-                  progname, rc );
-        exitrc = 1;
-        goto main_exit;
-      }
+    fprintf(stderr, "%s: writing %s:\n", 
+            progname, memtypestr(memtype));
+#if 1
+    rc = avr_write ( fd, memtype, p );
+#else
+    if (memtype == AVR_FLASH)
+      b2ihex ( p->flash, p->flash_size, 32, 0, "<stdout>", stdout);
+    else
+      b2ihex ( p->eeprom, p->eeprom_size, 32, 0, "<stdout>", stdout);
+#endif
+    if (rc) {
+      fprintf ( stderr, "%s: failed to write flash memory, rc=%d\n", 
+                progname, rc );
+      exitrc = 1;
+      goto main_exit;
     }
   }
 
@@ -1104,7 +1502,6 @@ int main ( int argc, char * argv [] )
   ppi_clr(fd, PPIDATA, AVR_RESET);
 
   close(fd);
-  close(iofd);
 
   fprintf(stderr, "\n" );