diff --git a/avrdude/avrprog.c b/avrdude/avrprog.c
index af00d821..4a0db623 100644
--- a/avrdude/avrprog.c
+++ b/avrdude/avrprog.c
@@ -71,6 +71,9 @@
 char * version = "$Id$";
 
 char * progname;
+char   progbuf[PATH_MAX]; /* temporary buffer of spaces the same
+                             length as progname; used for lining up
+                             multiline messages */
 
 
 /*
@@ -153,6 +156,26 @@ enum {
 };
 
 
+int cmd_dump(int fd, struct avrpart * p, int argc, char *argv[]);
+int cmd_write(int fd, struct avrpart * p, int argc, char *argv[]);
+int cmd_quit(int fd, struct avrpart * p, int argc, char *argv[]);
+
+struct command {
+  char * name;
+  int (*func)(int fd, struct avrpart * p, int argc, char *argv[]);
+};
+
+
+struct command cmd[] = {
+  { "dump",  cmd_dump },
+  { "write", cmd_write },
+  { "quit",  cmd_quit }
+};
+
+#define NCMDS (sizeof(cmd)/sizeof(struct command))
+
+
+
 
 #define MAX_LINE_LEN 256  /* max line length for ASCII format input files */
 
@@ -1235,6 +1258,482 @@ char * memtypestr ( AVRMEM memtype )
 }
 
 
+int nexttok ( char * buf, char ** tok, char ** next )
+{
+  char * q, * n;
+
+  q = buf;
+  while (isspace(*q))
+    q++;
+  
+  /* isolate first token */
+  n = q+1;
+  while (*n && !isspace(*n))
+    n++;
+
+  if (*n) {
+    *n = 0;
+    n++;
+  }
+
+  /* find start of next token */
+  while (isspace(*n))
+    n++;
+
+  *tok  = q;
+  *next = n;
+
+  return 0;
+}
+
+
+int hexdump_line ( char * buffer, unsigned char * p, int n, int pad )
+{
+  char * hexdata = "0123456789abcdef";
+  char * b;
+  int i, j;
+
+  b = buffer;
+
+  j = 0;
+  for (i=0; i<n; i++) {
+    if (i && ((i % 8) == 0))
+      b[j++] = ' ';
+    b[j++] = hexdata[(p[i] & 0xf0) >> 4];
+    b[j++] = hexdata[(p[i] & 0x0f)];
+    if (i < 15)
+      b[j++] = ' ';
+  }
+
+  for (i=j; i<pad; i++)
+    b[i] = ' ';
+
+  b[i] = 0;
+
+  for (i=0; i<pad; i++) {
+    if (!((b[i] == '0') || (b[i] == ' ')))
+      return 0;
+  }
+
+  return 1;
+}
+
+
+int chardump_line ( char * buffer, unsigned char * p, int n, int pad )
+{
+  int i;
+  char b [ 128 ];
+
+  for (i=0; i<n; i++) {
+    memcpy ( b, p, n );
+    buffer[i] = '.';
+    if (isalpha(b[i]) || isdigit(b[i]) || ispunct(b[i]))
+      buffer[i] = b[i];
+    else if (isspace(b[i]))
+      buffer[i] = ' ';
+  }
+
+  for (i=n; i<pad; i++)
+    buffer[i] = ' ';
+
+  buffer[i] = 0;
+
+  return 0;
+}
+
+
+int hexdump_buf ( FILE * f, int startaddr, char * buf, int len )
+{
+  int addr;
+  int i, n;
+  unsigned char * p;
+  char dst1[80];
+  char dst2[80];
+
+  addr = startaddr;
+  i = 0;
+  p = (unsigned char *)buf;
+  while (len) {
+    n = 16;
+    if (n > len)
+      n = len;
+    hexdump_line(dst1, p, n, 48);
+    chardump_line(dst2, p, n, 16);
+    fprintf(stdout, "%04x  %s  |%s|\n", addr, dst1, dst2);
+    len -= n;
+    addr += n;
+    p += n;
+  }
+
+  return 0;
+}
+
+
+int cmd_dump ( int fd, struct avrpart * p, int argc, char * argv[] )
+{
+  char * e;
+  int i, j;
+  int len, maxsize;
+  AVRMEM memtype;
+  unsigned short addr, daddr;
+  char * buf;
+
+  if (argc != 4) {
+    fprintf(stderr, "Usage: dump flash|eeprom <addr> <len>\n");
+    return -1;
+  }
+
+  if (strcmp(argv[1],"flash")==0) {
+    memtype = AVR_FLASH;
+    maxsize = p->flash_size;
+  }
+  else if (strcmp(argv[1],"eeprom")==0) {
+    memtype = AVR_EEPROM;
+    maxsize = p->eeprom_size;
+  }
+  else {
+    fprintf(stderr, "%s (dump): invalid memory type \"%s\"\n",
+            progname, argv[1]);
+    return -1;
+  }
+
+  addr = strtoul(argv[2], &e, 0);
+  if (*e || (e == argv[2])) {
+    fprintf(stderr, "%s (dump): can't parse address \"%s\"\n",
+            progname, argv[2]);
+    return -1;
+  }
+
+  len = strtol(argv[3], &e, 0);
+  if (*e || (e == argv[3])) {
+    fprintf(stderr, "%s (dump): can't parse length \"%s\"\n",
+            progname, argv[3]);
+    return -1;
+  }
+
+  if (addr > maxsize) {
+    fprintf(stderr, 
+            "%s (dump): address 0x%04x is out of range for %s memory\n",
+            progname, addr, memtypestr(memtype));
+    return -1;
+  }
+
+  if ((addr + len) > maxsize) {
+    fprintf(stderr, 
+            "%s (dump): selected address and length exceed "
+            "range for %s memory\n", 
+            progname, memtypestr(memtype));
+    return -1;
+  }
+
+  buf = malloc(len);
+  if (buf == NULL) {
+    fprintf(stderr, "%s (dump): out of memory\n", progname);
+    return -1;
+  }
+
+  j     = 0;
+  daddr = addr;
+  if (memtype == AVR_FLASH) {
+    daddr = addr / 2;
+    if (addr & 0x01) {
+      buf[j++] = avr_read_byte( fd, p, AVR_FLASH_HI, daddr);
+      daddr++;
+    }
+  }
+
+  i = daddr;
+  while (j < len) {
+    if (memtype == AVR_FLASH) {
+      buf[j++] = avr_read_byte( fd, p, AVR_FLASH_LO, i);
+      if (j < len) {
+        buf[j++] = avr_read_byte( fd, p, AVR_FLASH_HI, i);
+      }
+    }
+    else {
+      buf[j++] = avr_read_byte( fd, p, AVR_EEPROM, i);
+    }
+    i++;
+  }
+
+  hexdump_buf(stdout, addr, buf, len);
+
+  fprintf(stdout, "\n");
+
+  free(buf);
+
+  return 0;
+}
+
+int cmd_write ( int fd, struct avrpart * p, int argc, char * argv[] )
+{
+  char * e;
+  int i, j;
+  int len, maxsize;
+  AVRMEM memtype;
+  unsigned short addr, daddr;
+  char * buf;
+  int rc;
+
+  if (argc < 4) {
+    fprintf(stderr, 
+            "Usage: write flash|eeprom <addr> <byte1> <byte2> ... byteN>\n");
+    return -1;
+  }
+
+  if (strcmp(argv[1],"flash")==0) {
+    memtype = AVR_FLASH;
+    maxsize = p->flash_size;
+  }
+  else if (strcmp(argv[1],"eeprom")==0) {
+    memtype = AVR_EEPROM;
+    maxsize = p->eeprom_size;
+  }
+  else {
+    fprintf(stderr, "%s (write): invalid memory type \"%s\"\n",
+            progname, argv[1]);
+    return -1;
+  }
+
+  addr = strtoul(argv[2], &e, 0);
+  if (*e || (e == argv[2])) {
+    fprintf(stderr, "%s (write): can't parse address \"%s\"\n",
+            progname, argv[2]);
+    return -1;
+  }
+
+  if (addr > maxsize) {
+    fprintf(stderr, 
+            "%s (write): address 0x%04x is out of range for %s memory\n",
+            progname, addr, memtypestr(memtype));
+    return -1;
+  }
+
+  /* number of bytes to write at the specified address */
+  len = argc - 3;
+
+  if ((addr + len) > maxsize) {
+    fprintf(stderr, 
+            "%s (write): selected address and # bytes exceed "
+            "range for %s memory\n", 
+            progname, memtypestr(memtype));
+    return -1;
+  }
+
+  buf = malloc(len);
+  if (buf == NULL) {
+    fprintf(stderr, "%s (write): out of memory\n", progname);
+    return -1;
+  }
+
+  for (i=3; i<argc; i++) {
+    buf[i-3] = strtoul(argv[i], &e, 0);
+    if (*e || (e == argv[i])) {
+      fprintf(stderr, "%s (write): can't parse byte \"%s\"\n",
+              progname, argv[i]);
+      return -1;
+    }
+  }
+
+  j     = 0;
+  daddr = addr;
+  if (memtype == AVR_FLASH) {
+    daddr = addr / 2;
+    if (addr & 0x01) {
+      /* handle odd numbered memory locations in the flash area */
+      rc = avr_write_byte(fd, p, AVR_FLASH_HI, daddr, buf[j++]);
+      if (rc) {
+        fprintf(stderr, "%s (write): error writing 0x%02x at 0x%04x\n",
+                progname, buf[j-1], daddr*2+1);
+      }
+      daddr++;
+    }
+  }
+
+  i = daddr;
+  while (j < len) {
+    if (memtype == AVR_FLASH) {
+      rc = avr_write_byte( fd, p, AVR_FLASH_LO, i, buf[j++]);
+      if (rc) {
+        fprintf(stderr, "%s (write): error writing 0x%02x at 0x%04x\n",
+                progname, buf[j-1], i*2);
+      }
+      if (j < len) {
+        rc = avr_write_byte( fd, p, AVR_FLASH_HI, i, buf[j++]);
+        if (rc) {
+          fprintf(stderr, "%s (write): error writing 0x%02x at 0x%04x\n",
+                  progname, buf[j-1], i*2+1);
+        }
+      }
+    }
+    else {
+      rc = avr_write_byte( fd, p, AVR_EEPROM, i, buf[j++]);
+      if (rc) {
+        fprintf(stderr, "%s (write): error writing 0x%02x at 0x%04x\n",
+                progname, buf[j-1], i);
+      }
+    }
+    i++;
+  }
+
+  fprintf(stdout, "\n");
+
+  return 0;
+}
+
+
+int cmd_quit ( int fd, struct avrpart * p, int argc, char * argv[] )
+{
+  return 1;
+}
+
+
+int tokenize ( char * s, char *** argv )
+{
+  int     i, n, l, nargs, offset;
+  int     len, slen;
+  char  * buf;
+  int     bufsize;
+  char ** bufv;
+  char  * q, * r;
+  char  * nbuf;
+  char ** av;
+
+  slen = strlen(s);
+
+  /* 
+   * initialize allow for 20 arguments, use realloc to grow this if
+   * necessary 
+   */
+  nargs   = 20;
+  bufsize = slen + 20;
+  buf     = malloc(bufsize);
+  bufv    = (char **) malloc(nargs*sizeof(char *));
+  for (i=0; i<nargs; i++) {
+    bufv[i] = NULL;
+  }
+  buf[0] = 0;
+
+  n    = 0;
+  l    = 0;
+  nbuf = buf;
+  r    = s;
+  while (*r) {
+    nexttok(r, &q, &r);
+    strcpy(nbuf, q);
+    bufv[n]  = nbuf;
+    len      = strlen(q);
+    l       += len + 1;
+    nbuf    += len + 1;
+    nbuf[0]  = 0;
+    n++;
+    if ((n % 20) == 0) {
+      /* realloc space for another 20 args */
+      bufsize += 20;
+      nargs   += 20;
+      buf      = realloc(buf, bufsize);
+      bufv     = realloc(bufv, nargs*sizeof(char *));
+      nbuf     = &buf[l];
+      for (i=n; i<nargs; i++)
+        bufv[i] = NULL;
+    }
+  }
+
+  /* 
+   * We have parsed all the args, n == argc, bufv contains an array of
+   * pointers to each arg, and buf points to one memory block that
+   * contains all the args, back to back, seperated by a nul
+   * terminator.  Consilidate bufv and buf into one big memory block
+   * so that the code that calls us, will have an easy job of freeing
+   * this memory.
+   */
+  av = (char **) malloc(slen + n + (n+1)*sizeof(char *));
+  q  = (char *)&av[n+1];
+  memcpy(q, buf, l);
+  for (i=0; i<n; i++) {
+    offset = bufv[i] - buf;
+    av[i] = q + offset;
+  }
+  av[i] = NULL;
+
+  free(buf);
+  free(bufv);
+
+  *argv = av;
+
+  return n;
+}
+
+
+int do_cmd ( int fd, struct avrpart * p, int argc, char * argv[] )
+{
+  int i;
+
+  for (i=0; i<NCMDS; i++) {
+    if (strcasecmp(argv[0], cmd[i].name) == 0) {
+      return cmd[i].func(fd, p, argc, argv);
+    }
+  }
+
+  fprintf(stderr, "%s: invalid command \"%s\"\n",
+          progname, argv[0]);
+
+  return -1;
+}
+
+
+int go_interactive ( int fd, struct avrpart * p )
+{
+  char    cmdbuf[MAX_LINE_LEN];
+  int     i, len;
+  char  * q;
+  int     rc;
+  int     argc;
+  char ** argv;
+
+  fprintf(stdout, "avrprog> ");
+  while (fgets(cmdbuf, MAX_LINE_LEN, stdin) != NULL) {
+    len = strlen(cmdbuf);
+    if (cmdbuf[len-1] == '\n')
+      cmdbuf[--len] = 0;
+
+    /* 
+     * find the start of the command, skipping any white space
+     */
+    q = cmdbuf;
+    while (*q && isspace(*q))
+      q++;
+
+    /* skip blank lines and comments */
+    if (!*q || (*q == '#'))
+      continue;
+
+    /* tokenize command line */
+    argc = tokenize(q, &argv);
+
+    fprintf(stdout, ">>> ");
+    for (i=0; i<argc; i++)
+      fprintf(stdout, "%s ", argv[i]);
+    fprintf(stdout, "\n");
+
+#if 1
+    /* run the command */
+    rc = do_cmd(fd, p, argc, argv);
+    free(argv);
+    if (rc > 0) {
+      rc = 0;
+      break;
+    }
+#endif
+
+    fprintf(stdout, "avrprog> ");
+  }
+
+  return rc;
+}
+
+
+
 /*
  * main routine
  */
@@ -1247,7 +1746,6 @@ int main ( int argc, char * argv [] )
   int              ch;          /* options flag */
   int              size;        /* size of memory region */
   int              len;         /* length for various strings */
-  char             pbuf[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 */
@@ -1286,8 +1784,8 @@ int main ( int argc, char * argv [] )
 
   len = strlen(progname) + 2;
   for (i=0; i<len; i++)
-    pbuf[i] = ' ';
-  pbuf[i] = 0;
+    progbuf[i] = ' ';
+  progbuf[i] = 0;
 
   /*
    * Print out an identifying string so folks can tell what version
@@ -1307,7 +1805,7 @@ int main ( int argc, char * argv [] )
 
   fprintf(stderr, "\n");
   fprintf(stderr, "%s: Copyright 2000 Brian Dean, bsd@bsdhome.com\n"
-          "%sRevision ", progname, pbuf);
+          "%sRevision ", progname, progbuf);
   for (i=0; i<p2-p1; i++)
     fprintf(stderr, "%c", p1[i]);
   fprintf(stderr, "\n\n");
@@ -1462,13 +1960,13 @@ int main ( int argc, char * argv [] )
           "%sChip Erase delay       = %d us\n"
           "%sFlash Polled Readback  = 0x%02x\n"
           "%sEEPROM Polled Readback = 0x%02x, 0x%02x\n",
-          pbuf, p->partdesc,
-          pbuf, p->flash_size, 
-          pbuf, p->eeprom_size,
-          pbuf, p->min_write_delay, p->max_write_delay, 
-          pbuf, p->chip_erase_delay,
-          pbuf, p->f_readback,
-          pbuf, p->e_readback[0], p->e_readback[1]);
+          progbuf, p->partdesc,
+          progbuf, p->flash_size, 
+          progbuf, p->eeprom_size,
+          progbuf, p->min_write_delay, p->max_write_delay, 
+          progbuf, p->chip_erase_delay,
+          progbuf, p->f_readback,
+          progbuf, p->e_readback[0], p->e_readback[1]);
   fprintf(stderr, "\n");
 
   p->flash = (unsigned char *) malloc(p->flash_size);
@@ -1532,7 +2030,7 @@ int main ( int argc, char * argv [] )
       fprintf(stderr, 
               "%sDouble check connections and try again, or use -F to override\n"
               "%sthis check.\n\n",
-              pbuf, pbuf );
+              progbuf, progbuf );
       exit(1);
     }
   }
@@ -1551,7 +2049,7 @@ int main ( int argc, char * argv [] )
   }
 
 
-  if ((inputf==NULL) && (outputf==NULL)) {
+  if (!interactive && ((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
@@ -1566,8 +2064,13 @@ int main ( int argc, char * argv [] )
     goto main_exit;
   }
 
-
-  if (doread) {
+  if (interactive) {
+    /*
+     * interactive command mode
+     */
+    exitrc = go_interactive(fd, p);
+  }
+  else if (doread) {
     /*
      * read out the specified device memory and write it to a file 
      */
@@ -1636,7 +2139,7 @@ int main ( int argc, char * argv [] )
 
   close(fd);
 
-  fprintf(stderr, "\n" );
+  fprintf(stderr, "\n%s done.  Thank you.\n\n", progname);
 
   return exitrc;
 }