diff --git a/avrdude/Makefile b/avrdude/Makefile
index 6c919665..07d30ad0 100644
--- a/avrdude/Makefile
+++ b/avrdude/Makefile
@@ -17,28 +17,36 @@ DIRS         = ${BINDIR} ${MANDIR} ${DOCDIR} ${CONFIGDIR}
 
 INSTALL      = /usr/bin/install -c -o root -g wheel
 
-CFLAGS       = -g -Wall --pedantic -DCONFIG_DIR=\"${CONFIGDIR}\"
-
+CFLAGS       = -g -Wall --pedantic -DCONFIG_DIR=\"${CONFIGDIR}\" ${YYDEF}
 LDFLAGS      =  
+YFLAGS       = -t -d -v
 
 INSTALL_PROGRAM = ${INSTALL} -m 555 -s
 INSTALL_DATA    = ${INSTALL} -m 444
 INSTALL_MANUAL  = ${INSTALL_DATA}
 
 
-LIBS = -lreadline
+LIBS       = -lreadline
+
+YYDEF  = -DYYSTYPE="struct token_t *"
+
 
 .include "Makefile.inc"
 
+EXTRA_OBJS = config_gram.o lexer.o
+OBJECTS = ${EXTRA_OBJS} ${OBJS} 
+
 all :
+	@if [ ! -f y.tab.h ]; then touch y.tab.h; fi
 	make depend
 	make ${TARGET}
 
-${TARGET} : ${OBJS}
-	${CC} ${LDFLAGS} -o ${TARGET} ${OBJS} ${LIBS}
+${TARGET} : ${OBJECTS}
+	${CC} ${LDFLAGS} -o ${TARGET} ${OBJECTS} ${LIBS}
 
 clean :
-	rm -f *~ *.core ${TARGET} *.o
+	rm -f *.o lexer.c ${TARGET} *~ *.core y.tab.c y.tab.h
+	touch y.tab.h
 
 install : dirs                  \
 	  ${BINDIR}/${TARGET}   \
diff --git a/avrdude/Makefile.inc b/avrdude/Makefile.inc
index e22d5242..04dd5297 100644
--- a/avrdude/Makefile.inc
+++ b/avrdude/Makefile.inc
@@ -1,8 +1,14 @@
 
-.SUFFIXES: .o .c
+.SUFFIXES: .o .c .l .y
 
 first_rule : all
 
+.y.o:
+	${YACC} ${YFLAGS} ${.IMPSRC}
+	${CC} ${CFLAGS} -c y.tab.c
+	rm -f y.tab.c
+	mv y.tab.o ${.TARGET}
+
 
 .depend : .PHONY
 	@echo "# dependencies generated `date +'%D %T'`"        >  .depend
diff --git a/avrdude/avr.c b/avrdude/avr.c
index 381dbbec..66223a92 100644
--- a/avrdude/avr.c
+++ b/avrdude/avr.c
@@ -36,12 +36,14 @@
 
 
 #include "avr.h"
+#include "config.h"
 #include "pindefs.h"
 #include "ppi.h"
 
 
-extern char * progname;
-extern char   progbuf[];
+extern char       * progname;
+extern char         progbuf[];
+extern PROGRAMMER * pgm;
 
 
 char * avr_version = "$Id$";
@@ -49,6 +51,7 @@ char * avr_version = "$Id$";
 
 /* Need to add information for 2323, 2343, and 4414 */
 
+#if 0
 struct avrpart parts[] = {
   {"AT90S1200", "1200", 20000, 
    {{0,     64,   0,   0,  9000, 20000, {0x00, 0xff }, NULL},   /* eeprom */
@@ -87,8 +90,6 @@ struct avrpart parts[] = {
 #define N_AVRPARTS (sizeof(parts)/sizeof(struct avrpart))
 
 
-
-
 int avr_list_parts(FILE * f, char * prefix)
 {
   int i;
@@ -114,6 +115,56 @@ struct avrpart * avr_find_part(char * p)
 
   return NULL;
 }
+#endif
+
+
+AVRPART * avr_new_part(void)
+{
+  AVRPART * p;
+
+  p = (AVRPART *)malloc(sizeof(AVRPART));
+  if (p == NULL) {
+    fprintf(stderr, "new_part(): out of memory\n");
+    exit(1);
+  }
+
+  memset(p, 0, sizeof(*p));
+
+  p->id[0]   = 0;
+  p->desc[0] = 0;
+
+  return p;
+}
+
+
+
+AVRPART * avr_dup_part(AVRPART * d)
+{
+  AVRPART * p;
+  int i;
+
+  p = (AVRPART *)malloc(sizeof(AVRPART));
+  if (p == NULL) {
+    fprintf(stderr, "avr_dup_part(): out of memory\n");
+    exit(1);
+  }
+
+  *p = *d;
+
+  for (i=0; i<AVR_MAXMEMTYPES; i++) {
+    p->mem[i].buf = (unsigned char *)malloc(p->mem[i].size);
+    if (p->mem[i].buf == NULL) {
+      fprintf(stderr, 
+              "avr_dup_part(): out of memory (memsize=%d)\n", 
+              p->mem[i].size);
+      exit(1);
+    }
+    memset(p->mem[i].buf, 0, p->mem[i].size);
+  }
+
+  return p;
+}
+
 
 
 /*
@@ -127,16 +178,16 @@ int avr_txrx_bit(int fd, int bit)
    * read the result bit (it is either valid from a previous clock
    * pulse or it is ignored in the current context)
    */
-  r = ppi_getpin(fd, pinno[PIN_AVR_MISO]);
+  r = ppi_getpin(fd, pgm->pinno[PIN_AVR_MISO]);
 
   /* set the data input line as desired */
-  ppi_setpin(fd, pinno[PIN_AVR_MOSI], bit);
+  ppi_setpin(fd, pgm->pinno[PIN_AVR_MOSI], bit);
 
   /* 
    * pulse the clock line, clocking in the MOSI data, and clocking out
    * the next result bit
    */
-  ppi_pulsepin(fd, pinno[PIN_AVR_SCK]);
+  ppi_pulsepin(fd, pgm->pinno[PIN_AVR_SCK]);
 
   return r;
 }
@@ -180,8 +231,8 @@ int avr_cmd(int fd, unsigned char cmd[4], unsigned char res[4])
 /*
  * read a byte of data from the indicated memory region
  */
-unsigned char avr_read_byte(int fd, struct avrpart * p,
-                              int memtype, unsigned long addr)
+unsigned char avr_read_byte(int fd, AVRPART * p,
+                            int memtype, unsigned long addr)
 {
   unsigned short offset;
   unsigned char cmd[4];
@@ -189,8 +240,8 @@ unsigned char avr_read_byte(int fd, struct avrpart * p,
   /* order here is very important, AVR_EEPROM, AVR_FLASH, AVR_FLASH+1 */
   static unsigned char cmdbyte[3] = { 0xa0, 0x20, 0x28 };
 
-  LED_ON(fd, pinno[PIN_LED_PGM]);
-  LED_OFF(fd, pinno[PIN_LED_ERR]);
+  LED_ON(fd, pgm->pinno[PIN_LED_PGM]);
+  LED_OFF(fd, pgm->pinno[PIN_LED_ERR]);
 
   offset = 0;
 
@@ -206,7 +257,7 @@ unsigned char avr_read_byte(int fd, struct avrpart * p,
 
   avr_cmd(fd, cmd, res);
 
-  LED_OFF(fd, pinno[PIN_LED_PGM]);
+  LED_OFF(fd, pgm->pinno[PIN_LED_PGM]);
 
   return res[3];
 }
@@ -218,7 +269,7 @@ unsigned char avr_read_byte(int fd, struct avrpart * p,
  *
  * Return the number of bytes read, or -1 if an error occurs.  
  */
-int avr_read(int fd, struct avrpart * p, int memtype)
+int avr_read(int fd, AVRPART * p, int memtype)
 {
   unsigned char    rbyte;
   unsigned long    i;
@@ -243,14 +294,14 @@ int avr_read(int fd, struct avrpart * p, int memtype)
 /*
  * write a byte of data to the indicated memory region
  */
-int avr_write_bank(int fd, struct avrpart * p, int memtype, 
+int avr_write_bank(int fd, AVRPART * p, int memtype, 
                    unsigned short bank)
 {
   unsigned char cmd[4];
   unsigned char res[4];
 
-  LED_ON(fd, pinno[PIN_LED_PGM]);
-  LED_OFF(fd, pinno[PIN_LED_ERR]);
+  LED_ON(fd, pgm->pinno[PIN_LED_PGM]);
+  LED_OFF(fd, pgm->pinno[PIN_LED_ERR]);
 
   cmd[0] = 0x4c;
   cmd[1] = bank >> 8;     /* high order bits of address */
@@ -265,7 +316,7 @@ int avr_write_bank(int fd, struct avrpart * p, int memtype,
    */
   usleep(p->mem[memtype].max_write_delay);
 
-  LED_OFF(fd, pinno[PIN_LED_PGM]);
+  LED_OFF(fd, pgm->pinno[PIN_LED_PGM]);
   return 0;
 }
 
@@ -273,8 +324,8 @@ int avr_write_bank(int fd, struct avrpart * p, int memtype,
 /*
  * write a byte of data to the indicated memory region
  */
-int avr_write_byte(int fd, struct avrpart * p, int memtype, 
-                     unsigned long addr, unsigned char data)
+int avr_write_byte(int fd, AVRPART * p, int memtype, 
+                   unsigned long addr, unsigned char data)
 {
   unsigned char cmd[4];
   unsigned char res[4];
@@ -302,8 +353,8 @@ int avr_write_byte(int fd, struct avrpart * p, int memtype,
     addr = addr % p->mem[memtype].bank_size;
   }
 
-  LED_ON(fd, pinno[PIN_LED_PGM]);
-  LED_OFF(fd, pinno[PIN_LED_ERR]);
+  LED_ON(fd, pgm->pinno[PIN_LED_PGM]);
+  LED_OFF(fd, pgm->pinno[PIN_LED_ERR]);
 
   offset = 0;
 
@@ -326,7 +377,7 @@ int avr_write_byte(int fd, struct avrpart * p, int memtype,
      * page complete immediately, we only need to delay when we commit
      * the whole page via the avr_write_bank() routine.
      */
-    LED_OFF(fd, pinno[PIN_LED_PGM]);
+    LED_OFF(fd, pgm->pinno[PIN_LED_PGM]);
     return 0;
   }
 
@@ -357,14 +408,14 @@ int avr_write_byte(int fd, struct avrpart * p, int memtype,
        * we couldn't write the data, indicate our displeasure by
        * returning an error code 
        */
-      LED_OFF(fd, pinno[PIN_LED_PGM]);
-      LED_ON(fd, pinno[PIN_LED_ERR]);
+      LED_OFF(fd, pgm->pinno[PIN_LED_PGM]);
+      LED_ON(fd, pgm->pinno[PIN_LED_ERR]);
 
       return -1;
     }
   }
 
-  LED_OFF(fd, pinno[PIN_LED_PGM]);
+  LED_OFF(fd, pgm->pinno[PIN_LED_PGM]);
   return 0;
 }
 
@@ -378,7 +429,7 @@ int avr_write_byte(int fd, struct avrpart * p, int memtype,
  *
  * Return the number of bytes written, or -1 if an error occurs.
  */
-int avr_write(int fd, struct avrpart * p, int memtype, int size)
+int avr_write(int fd, AVRPART * p, int memtype, int size)
 {
   int              rc;
   int              wsize;
@@ -386,7 +437,7 @@ int avr_write(int fd, struct avrpart * p, int memtype, int size)
   unsigned char    data;
   int              werror;
 
-  LED_OFF(fd, pinno[PIN_LED_ERR]);
+  LED_OFF(fd, pgm->pinno[PIN_LED_ERR]);
 
   werror = 0;
 
@@ -410,7 +461,7 @@ int avr_write(int fd, struct avrpart * p, int memtype, int size)
     if (rc) {
       fprintf(stderr, " ***failed;  ");
       fprintf(stderr, "\n");
-      LED_ON(fd, pinno[PIN_LED_ERR]);
+      LED_ON(fd, pgm->pinno[PIN_LED_ERR]);
       werror = 1;
     }
 
@@ -424,7 +475,7 @@ int avr_write(int fd, struct avrpart * p, int memtype, int size)
                   i % p->mem[memtype].bank_size, 
                   i-p->mem[memtype].bank_size+1, i);
           fprintf(stderr, "\n");
-          LED_ON(fd, pinno[PIN_LED_ERR]);
+          LED_ON(fd, pgm->pinno[PIN_LED_ERR]);
           werror = 1;
         }
       }
@@ -435,7 +486,7 @@ int avr_write(int fd, struct avrpart * p, int memtype, int size)
        * make sure the error led stay on if there was a previous write
        * error, otherwise it gets cleared in avr_write_byte() 
        */
-      LED_ON(fd, pinno[PIN_LED_ERR]);
+      LED_ON(fd, pgm->pinno[PIN_LED_ERR]);
     }
   }
 
@@ -466,18 +517,18 @@ int avr_program_enable(int fd)
 /*
  * issue the 'chip erase' command to the AVR device
  */
-int avr_chip_erase(int fd, struct avrpart * p)
+int avr_chip_erase(int fd, AVRPART * p)
 {
   unsigned char data[4] = {0xac, 0x80, 0x00, 0x00};
   unsigned char res[4];
 
-  LED_ON(fd, pinno[PIN_LED_PGM]);
+  LED_ON(fd, pgm->pinno[PIN_LED_PGM]);
 
   avr_cmd(fd, data, res);
   usleep(p->chip_erase_delay);
   avr_initialize(fd, p);
 
-  LED_OFF(fd, pinno[PIN_LED_PGM]);
+  LED_OFF(fd, pgm->pinno[PIN_LED_PGM]);
 
   return 0;
 }
@@ -524,7 +575,7 @@ void avr_powerdown(int fd)
 /*
  * initialize the AVR device and prepare it to accept commands
  */
-int avr_initialize(int fd, struct avrpart * p)
+int avr_initialize(int fd, AVRPART * p)
 {
   int rc;
   int tries;
@@ -532,9 +583,9 @@ int avr_initialize(int fd, struct avrpart * p)
   avr_powerup(fd);
 
 
-  ppi_setpin(fd, pinno[PIN_AVR_SCK], 0);
-  ppi_setpin(fd, pinno[PIN_AVR_RESET], 0);
-  ppi_pulsepin(fd, pinno[PIN_AVR_RESET]);
+  ppi_setpin(fd, pgm->pinno[PIN_AVR_SCK], 0);
+  ppi_setpin(fd, pgm->pinno[PIN_AVR_RESET], 0);
+  ppi_pulsepin(fd, pgm->pinno[PIN_AVR_RESET]);
 
   usleep(20000); /* 20 ms XXX should be a per-chip parameter */
 
@@ -546,7 +597,7 @@ int avr_initialize(int fd, struct avrpart * p)
    * order to possibly get back into sync with the chip if we are out
    * of sync.
    */
-  if (strcmp(p->partdesc, "AT90S1200")==0) {
+  if (strcmp(p->desc, "AT90S1200")==0) {
     avr_program_enable(fd);
   }
   else {
@@ -555,7 +606,7 @@ int avr_initialize(int fd, struct avrpart * p)
       rc = avr_program_enable(fd);
       if (rc == 0)
         break;
-      ppi_pulsepin(fd, pinno[PIN_AVR_SCK]);
+      ppi_pulsepin(fd, pgm->pinno[PIN_AVR_SCK]);
       tries++;
     } while (tries < 32);
 
@@ -583,7 +634,7 @@ char * avr_memtstr(int memtype)
 }
 
 
-int avr_initmem(struct avrpart * p)
+int avr_initmem(AVRPART * p)
 {
   int i;
 
@@ -607,7 +658,7 @@ int avr_initmem(struct avrpart * p)
  *
  * Return the number of bytes verified, or -1 if they don't match.  
  */
-int avr_verify(struct avrpart * p, struct avrpart * v, int memtype, int size)
+int avr_verify(AVRPART * p, AVRPART * v, int memtype, int size)
 {
   int i;
   unsigned char * buf1, * buf2;
@@ -665,7 +716,7 @@ void avr_mem_display(char * prefix, FILE * f, AVRMEM * m, int type)
 
 
 
-void avr_display(FILE * f, struct avrpart * p, char * prefix)
+void avr_display(FILE * f, AVRPART * p, char * prefix)
 {
   int i;
   char * buf;
@@ -675,7 +726,7 @@ void avr_display(FILE * f, struct avrpart * p, char * prefix)
           "%sAVR Part         : %s\n"
           "%sChip Erase delay : %d us\n"
           "%sMemory Detail    :\n\n",
-          prefix, p->partdesc,
+          prefix, p->desc,
           prefix, p->chip_erase_delay,
           prefix);
 
diff --git a/avrdude/avr.h b/avrdude/avr.h
index c4b04d0a..ba488c67 100644
--- a/avrdude/avr.h
+++ b/avrdude/avr.h
@@ -45,15 +45,6 @@
 
 #define AVR_MAXMEMTYPES 2     /* just flash and eeprom */
 
-#if 0
-struct avrmem {
-  int             startaddr;
-  int             size;
-  unsigned char * buf;
-  struct avrmem * next;
-};
-#endif
-
 typedef struct avrmem {
   int banked;                   /* bank addressed (e.g. ATmega flash) */
   int size;                     /* total memory size in bytes */
@@ -66,42 +57,27 @@ typedef struct avrmem {
 } AVRMEM;
 
 
-struct avrpart {
-  char          * partdesc;         /* long part name */
-  char          * optiontag;        /* short part name */
+#define AVR_DESCLEN 64
+#define AVR_IDLEN   32
+typedef struct avrpart {
+  char          desc[AVR_DESCLEN];  /* long part name */
+  char          id[AVR_IDLEN];      /* short part name */
 
   int             chip_erase_delay; /* microseconds */
 
   AVRMEM          mem[AVR_MAXMEMTYPES];
-
-#if 0
-  int             memsize[AVR_MAXMEMTYPES]; /* sizes for eeprom,
-                                               flash, etc, indexed by
-                                               AVR_EEPROM or AVR_FLASH */
-  unsigned char   f_readback;       /* flash write polled readback value */
-  unsigned char   e_readback[2];    /* eeprom write polled readback values */
-  int             min_write_delay;  /* microseconds */
-  int             max_write_delay;  /* microseconds */
-#if 1
-  unsigned char * mem[AVR_MAXMEMTYPES]; /* pointers to avr memory
-                                           buffers, indexed by
-                                           AVR_EEPROM or AVR_FLASH */
-#else
-  struct avrmem * mem[AVR_MAXMEMTYPES]; /* pointers to avr memory
-                                           buffers, indexed by
-                                           AVR_EEPROM or AVR_FLASH */
-#endif
-#endif
-};
+} AVRPART;
 
 
 extern struct avrpart parts[];
 
 
 
-int avr_list_parts(FILE * f, char * prefix);
+AVRPART * avr_find_part(char * p);
 
-struct avrpart * avr_find_part(char * p);
+AVRPART * avr_new_part(void);
+
+AVRPART * avr_dup_part(AVRPART * d);
 
 int avr_txrx_bit(int fd, int bit);
 
@@ -109,22 +85,22 @@ unsigned char avr_txrx(int fd, unsigned char byte);
 
 int avr_cmd(int fd, unsigned char cmd[4], unsigned char res[4]);
 
-unsigned char avr_read_byte(int fd, struct avrpart * p,
-                              int memtype, unsigned long addr);
+unsigned char avr_read_byte(int fd, AVRPART * p,
+                            int memtype, unsigned long addr);
 
-int avr_read(int fd, struct avrpart * p, int memtype);
+int avr_read(int fd, AVRPART * p, int memtype);
 
-int avr_write_bank(int fd, struct avrpart * p, int memtype, 
+int avr_write_bank(int fd, AVRPART * p, int memtype, 
                    unsigned short bank);
 
-int avr_write_byte(int fd, struct avrpart * p, int memtype, 
-                     unsigned long addr, unsigned char data);
+int avr_write_byte(int fd, AVRPART * p, int memtype, 
+                   unsigned long addr, unsigned char data);
 
-int avr_write(int fd, struct avrpart * p, int memtype, int size);
+int avr_write(int fd, AVRPART * p, int memtype, int size);
 
 int avr_program_enable(int fd);
 
-int avr_chip_erase(int fd, struct avrpart * p);
+int avr_chip_erase(int fd, AVRPART * p);
 
 int avr_signature(int fd, unsigned char sig[4]);
 
@@ -132,16 +108,16 @@ void avr_powerup(int fd);
 
 void avr_powerdown(int fd);
 
-int avr_initialize(int fd, struct avrpart * p);
+int avr_initialize(int fd, AVRPART * p);
 
 char * avr_memtstr(int memtype);
 
-int avr_initmem(struct avrpart * p);
+int avr_initmem(AVRPART * p);
 
-int avr_verify(struct avrpart * p, struct avrpart * v, int memtype, 
+int avr_verify(AVRPART * p, AVRPART * v, int memtype, 
                int size);
 
-void avr_display(FILE * f, struct avrpart * p, char * prefix);
+void avr_display(FILE * f, AVRPART * p, char * prefix);
 
 
 #endif
diff --git a/avrdude/avrdude.conf.sample b/avrdude/avrdude.conf.sample
index afa63de1..4e0000f3 100644
--- a/avrdude/avrdude.conf.sample
+++ b/avrdude/avrdude.conf.sample
@@ -1,27 +1,310 @@
 # $Id$
 #
-# Programmer Pin Configurations
+# AVRPROG Configuration File
 #
-# The format of these entries is as follows:
-#   c:<name>:[desc=<description>:][[<pin>=<value>:]...]
+# This file contains configuration data used by AVRPROG which describes
+# the programming hardware pinouts and also provides part definitions.
+# AVRPROG's "-C" command line option specifies the location of the
+# configuration file.  The "-c" option names the programmer confiuration
+# which must match one of the entry's "id" parameter.  The "-p" option
+# identifies which part AVRPROG is going to be programming and must match
+# one of the parts' "id" parameter.
 #
-# Example: for a programmer called PGM-1 that uses pin 2 and 3 for
-#   power, pins 4, 5, and 6 for RESET, SCK, and MOSI, and pin 10 for
-#   MISO, we could use the following entry:
+# Possible entry formats are:
 #
-#  c:pgm-1 : desc=Programmer 1:vcc=2,3:reset=4:sck=5:mosi=6:miso=10
+#   programmer
+#       id     = <id1> [, <id2> [, <id3>] ...] ;  # <idN> are quoted strings
+#       desc   = <description> ;                  # quoted string
+#       vcc    = <num1> [, <num2> ... ] ;         # pin number
+#       reset  = <num> ;                          # pin number
+#       sck    = <num> ;                          # pin number
+#       mosi   = <num> ;                          # pin number
+#       miso   = <num> ;                          # pin number
+#       errled = <num> ;                          # pin number
+#       rdyled = <num> ;                          # pin number
+#       pgmled = <num> ;                          # pin number
+#       vfyled = <num> ;                          # pin number
+#     ;
 #
-# Continuation lines are supported, use a backslash (\) as the last
-# character of the line and the next line will included as part of the
-# configuration data.
+#   part
+#       id               = <id> ;                 # quoted string
+#       desc             = <description> ;        # quoted string
+#       chip_erase_delay = <num> ;                # micro-seconds
+#       eeprom
+#           banked          = <yes/no> ;          # yes / no
+#           size            = <num> ;             # bytes
+#           bank_size       = <num> ;             # bytes
+#           num_banks       = <num> ;             # numeric
+#           min_write_delay = <num> ;             # micro-seconds
+#           max_write_delay = <num> ;             # micro-seconds
+#           readback_p1     = <num> ;             # byte value
+#           readback_p2     = <num> ;             # byte value
+#         ;
+#       flash
+#           banked          = <yes/no> ;          # yes / no
+#           size            = <num> ;             # bytes
+#           bank_size       = <num> ;             # bytes
+#           num_banks       = <num> ;             # numeric
+#           min_write_delay = <num> ;             # micro-seconds
+#           max_write_delay = <num> ;             # micro-seconds
+#           readback_p1     = <num> ;             # byte value
+#           readback_p2     = <num> ;             # byte value
+#         ;
+#     ;
+#
+# If any of the above parameters is not specified, the default value of
+# 0 is used for numerics or the empty string ("") for string values.
+# If a required parameter is left empty, AVRPROG will complain.
+#
+# See below for some examples.
 #
 
-c:bsd   : desc=Brian Dean's programmer:vcc=2,3,4,5:reset=7:sck=8:\
-          mosi=9:miso=10
+programmer
+  id    = "bsd", "default";
+  desc  = "Brian Dean's Programmer";
+  vcc   = 2, 3, 4, 5;
+  reset = 7;
+  sck   = 8;
+  mosi  = 9;
+  miso  = 10;
+;
 
-c:dt006 : desc=Dontronics DT006:reset=4:sck=5:mosi=2:miso=11
+programmer
+  id    = "dt006";
+  desc  = "Dontronics DT006";
+  reset = 4;
+  sck   = 8;
+  mosi  = 9;
+  miso  = 10;
+;
 
-c:alf   : desc=Tony Freibel's programmer:vcc=2,3,4,5:buff=6:\
-          reset=7:sck=8:mosi=9:miso=10:errled=1:rdyled=14:pgmled=16:\
-          vfyled=17
+programmer
+  id     = "alf";
+  desc   = "Tony Friebel's Programmer";
+  vcc    = 2, 3, 4, 5;
+  buff   = 6;
+  reset  = 7;
+  sck    = 8;
+  mosi   = 9;
+  miso   = 10;
+  errled = 1;
+  rdyled = 14;
+  pgmled = 16;
+  vfyled = 17;
+;
+
+
+part
+    id               = "1200";
+    desc             = "AT90S1200";
+    chip_erase_delay = 20000;
+    eeprom
+        banked          = no;
+        size            = 64;
+        bank_size       = 0;
+        num_banks       = 0;
+        min_write_delay = 9000;
+        max_write_delay = 20000;
+        readback_p1     = 0x00;
+        readback_p2     = 0xff;
+      ;
+    flash
+        banked          = no;
+        size            = 1024;
+        bank_size       = 0;
+        num_banks       = 0;
+        min_write_delay = 9000;
+        max_write_delay = 20000;
+        readback_p1     = 0xff;
+        readback_p2     = 0x00;
+      ;
+  ;
+
+part
+    id               = "2313";
+    desc             = "AT90S2313";
+    chip_erase_delay = 20000;
+    eeprom
+        banked          = no;
+        size            = 128;
+        bank_size       = 0;
+        num_banks       = 0;
+        min_write_delay = 9000;
+        max_write_delay = 20000;
+        readback_p1     = 0x80;
+        readback_p2     = 0x7f;
+      ;
+    flash
+        banked          = no;
+        size            = 2048;
+        bank_size       = 0;
+        num_banks       = 0;
+        min_write_delay = 9000;
+        max_write_delay = 20000;
+        readback_p1     = 0x7f;
+        readback_p2     = 0x00;
+      ;
+  ;
+
+    
+part
+    id               = "2333";
+    desc             = "AT90S2333";
+    chip_erase_delay = 20000;
+    eeprom
+        banked          = no;
+        size            = 128;
+        bank_size       = 0;
+        num_banks       = 0;
+        min_write_delay = 9000;
+        max_write_delay = 20000;
+        readback_p1     = 0x00;
+        readback_p2     = 0xff;
+      ;
+    flash
+        banked          = no;
+        size            = 2048;
+        bank_size       = 0;
+        num_banks       = 0;
+        min_write_delay = 9000;
+        max_write_delay = 20000;
+        readback_p1     = 0xff;
+        readback_p2     = 0x00;
+      ;
+  ;
+
+    
+part
+    id               = "4433";
+    desc             = "AT90S4433";
+    chip_erase_delay = 20000;
+    eeprom
+        banked          = no;
+        size            = 256;
+        bank_size       = 0;
+        num_banks       = 0;
+        min_write_delay = 9000;
+        max_write_delay = 20000;
+        readback_p1     = 0x00;
+        readback_p2     = 0xff;
+      ;
+    flash
+        banked          = no;
+        size            = 4096;
+        bank_size       = 0;
+        num_banks       = 0;
+        min_write_delay = 9000;
+        max_write_delay = 20000;
+        readback_p1     = 0xff;
+        readback_p2     = 0x00;
+      ;
+  ;
+
+    
+part
+    id               = "4434";
+    desc             = "AT90S4434";
+    chip_erase_delay = 20000;
+    eeprom
+        banked          = no;
+        size            = 256;
+        bank_size       = 0;
+        num_banks       = 0;
+        min_write_delay = 9000;
+        max_write_delay = 20000;
+        readback_p1     = 0x00;
+        readback_p2     = 0xff;
+      ;
+    flash
+        banked          = no;
+        size            = 4096;
+        bank_size       = 0;
+        num_banks       = 0;
+        min_write_delay = 9000;
+        max_write_delay = 20000;
+        readback_p1     = 0xff;
+        readback_p2     = 0x00;
+      ;
+  ;
+
+    
+part
+    id               = "8515";
+    desc             = "AT90S8515";
+    chip_erase_delay = 20000;
+    eeprom
+        banked          = no;
+        size            = 512;
+        bank_size       = 0;
+        num_banks       = 0;
+        min_write_delay = 9000;
+        max_write_delay = 20000;
+        readback_p1     = 0x80;
+        readback_p2     = 0x7f;
+      ;
+    flash
+        banked          = no;
+        size            = 8192;
+        bank_size       = 0;
+        num_banks       = 0;
+        min_write_delay = 9000;
+        max_write_delay = 20000;
+        readback_p1     = 0x7f;
+        readback_p2     = 0x00;
+      ;
+  ;
+
+    
+part
+    id               = "8535";
+    desc             = "AT90S8535";
+    chip_erase_delay = 20000;
+    eeprom
+        banked          = no;
+        size            = 512;
+        bank_size       = 0;
+        num_banks       = 0;
+        min_write_delay = 9000;
+        max_write_delay = 20000;
+        readback_p1     = 0x00;
+        readback_p2     = 0xff;
+      ;
+    flash
+        banked          = no;
+        size            = 8192;
+        bank_size       = 0;
+        num_banks       = 0;
+        min_write_delay = 9000;
+        max_write_delay = 20000;
+        readback_p1     = 0xff;
+        readback_p2     = 0x00;
+      ;
+  ;
+
+    
+part
+    id               = "103";
+    desc             = "ATMEGA103";
+    chip_erase_delay = 112000;
+    eeprom
+        banked          = no;
+        size            = 4096;
+        bank_size       = 0;
+        num_banks       = 0;
+        min_write_delay = 4000;
+        max_write_delay = 9000;
+        readback_p1     = 0x00;
+        readback_p2     = 0xff;
+      ;
+    flash
+        banked          = yes;
+        size            = 131072;
+        bank_size       = 256;
+        num_banks       = 512;
+        min_write_delay = 22000;
+        max_write_delay = 56000;
+        readback_p1     = 0xff;
+        readback_p2     = 0x00;
+      ;
+  ;
 
diff --git a/avrdude/config.c b/avrdude/config.c
new file mode 100644
index 00000000..5b259c2f
--- /dev/null
+++ b/avrdude/config.c
@@ -0,0 +1,283 @@
+/* $Id$ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "avr.h"
+#include "config.h"
+#include "y.tab.h"
+
+char string_buf[MAX_STR_CONST];
+char *string_buf_ptr;
+
+LISTID       string_list;
+LISTID       number_list;
+PROGRAMMER * current_prog;
+AVRPART    * current_part;
+int          current_mem;
+LISTID       part_list;
+LISTID       programmers;
+
+int    lineno = 0;
+char * infile = NULL;
+
+#define DEBUG 0
+
+char * config_version = "$Id$";
+
+
+int init_config(void)
+{
+  string_list  = lcreat(NULL, 0);
+  number_list  = lcreat(NULL, 0);
+  current_prog = NULL;
+  current_part = NULL;
+  current_mem  = 0;
+  part_list    = lcreat(NULL, 0);
+  programmers  = lcreat(NULL, 0);
+
+  lineno       = 1;
+  infile       = NULL;
+
+  return 0;
+}
+
+
+
+int yywrap()
+{
+  return 1;
+}
+
+
+int yyerror(char * errmsg)
+{
+  fprintf(stderr, "%s at %s:%d\n", errmsg, infile, lineno);
+  exit(1);
+}
+
+
+TOKEN * new_token(int primary)
+{
+  TOKEN * tkn;
+
+  tkn = (TOKEN *)malloc(sizeof(TOKEN));
+  if (tkn == NULL) {
+    fprintf(stderr, "new_token(): out of memory\n");
+    exit(1);
+  }
+
+  memset(tkn, 0, sizeof(TOKEN));
+
+  tkn->primary = primary;
+
+  return tkn;
+}
+
+
+void free_token(TOKEN * tkn)
+{
+  if (tkn) {
+    switch (tkn->primary) {
+      case TKN_STRING:
+      case TKN_ID:
+        if (tkn->value.string)
+          free(tkn->value.string);
+        tkn->value.string = NULL;
+        break;
+    }
+    
+    free(tkn);
+  }
+}
+
+
+void free_tokens(int n, ...)
+{
+  TOKEN * t;
+  va_list ap;
+
+  va_start(ap, n);
+  while (n--) {
+    t = va_arg(ap, TOKEN *);
+    free_token(t);
+  }
+  va_end(ap);
+}
+
+
+
+TOKEN * number(char * text)
+{
+  struct token_t * tkn;
+
+  tkn = new_token(TKN_NUMBER);
+  tkn->value.type   = V_NUM;
+  tkn->value.number = atof(text);
+
+#if DEBUG
+  fprintf(stderr, "NUMBER(%g)\n", tkn->value.number);
+#endif
+
+  return tkn;
+}
+
+
+TOKEN * hexnumber(char * text)
+{
+  struct token_t * tkn;
+  char * e;
+
+  tkn = new_token(TKN_NUMBER);
+  tkn->value.type   = V_NUM;
+  tkn->value.number = strtoul(text, &e, 16);
+  if ((e == text) || (*e != 0)) {
+    fprintf(stderr, "error at %s:%d: can't scan hex number \"%s\"\n",
+            infile, lineno, text);
+    exit(1);
+  }
+  
+#if DEBUG
+  fprintf(stderr, "HEXNUMBER(%g)\n", tkn->value.number);
+#endif
+
+  return tkn;
+}
+
+
+TOKEN * string(char * text)
+{
+  struct token_t * tkn;
+  int len;
+
+  tkn = new_token(TKN_STRING);
+
+  len = strlen(text);
+
+  tkn->value.type   = V_STR;
+  tkn->value.string = (char *) malloc(len+1);
+  if (tkn->value.string == NULL) {
+    fprintf(stderr, "id(): out of memory\n");
+    exit(1);
+  }
+  strcpy(tkn->value.string, text);
+
+#if DEBUG
+  fprintf(stderr, "STRING(%s)\n", tkn->value.string);
+#endif
+
+  return tkn;
+}
+
+
+TOKEN * id(char * text)
+{
+  struct token_t * tkn;
+  int len;
+
+  tkn = new_token(TKN_ID);
+
+  len = strlen(text);
+
+  tkn->value.type   = V_STR;
+  tkn->value.string = (char *) malloc(len+1);
+  if (tkn->value.string == NULL) {
+    fprintf(stderr, "id(): out of memory\n");
+    exit(1);
+  }
+  strcpy(tkn->value.string, text);
+
+#if DEBUG
+  fprintf(stderr, "ID(%s)\n", tkn->value.string);
+#endif
+
+  return tkn;
+}
+
+
+TOKEN * keyword(int primary)
+{
+  struct token_t * tkn;
+
+  tkn = new_token(primary);
+
+  return tkn;
+}
+
+
+void print_token(TOKEN * tkn)
+{
+  if (!tkn)
+    return;
+
+  fprintf(stderr, "token = %d = ", tkn->primary);
+  switch (tkn->primary) {
+    case TKN_NUMBER: 
+      fprintf(stderr, "NUMBER, value=%g", tkn->value.number); 
+      break;
+
+    case TKN_STRING: 
+      fprintf(stderr, "STRING, value=%s", tkn->value.string); 
+      break;
+
+    case TKN_ID:  
+      fprintf(stderr, "ID,     value=%s", tkn->value.string); 
+      break;
+
+    default:     
+      fprintf(stderr, "<other>"); 
+      break;
+  }
+
+  fprintf(stderr, "\n");
+}
+
+
+void pyytext(void)
+{
+#if DEBUG
+  extern char * yytext;
+
+  fprintf(stderr, "TOKEN: \"%s\"\n", yytext);
+#endif
+}
+
+
+PROGRAMMER * new_programmer(void)
+{
+  PROGRAMMER * p;
+  int i;
+
+  p = (PROGRAMMER *)malloc(sizeof(PROGRAMMER));
+  if (p == NULL) {
+    fprintf(stderr, "new_programmer(): out of memory\n");
+    exit(1);
+  }
+
+  memset(p, 0, sizeof(*p));
+
+  p->id = lcreat(NULL, 0);
+  p->desc[0] = 0;
+
+  for (i=0; i<N_PINS; i++)
+    p->pinno[i] = 0;
+
+  return p;
+}
+
+
+char * dup_string(char * str)
+{
+  char * s;
+
+  s = strdup(str);
+  if (s == NULL) {
+    fprintf(stderr, "dup_string(): out of memory\n");
+    exit(1);
+  }
+
+  return s;
+}
+
diff --git a/avrdude/config.h b/avrdude/config.h
new file mode 100644
index 00000000..256cc322
--- /dev/null
+++ b/avrdude/config.h
@@ -0,0 +1,84 @@
+/* $Id$ */
+
+#ifndef __config_h__
+#define __config_h__
+
+#include "lists.h"
+#include "pindefs.h"
+#include "avr.h"
+
+
+#define MAX_STR_CONST 1024
+
+enum { V_NONE, V_NUM, V_STR };
+typedef struct value_t {
+  int      type;
+  double   number;
+  char   * string;
+} VALUE;
+
+
+typedef struct token_t {
+  int primary;
+  VALUE value;
+} TOKEN;
+
+
+#define PGM_DESCLEN 80
+typedef struct programmer_t {
+  LISTID id;
+  char desc[PGM_DESCLEN];
+  unsigned int pinno[N_PINS];
+} PROGRAMMER;
+
+extern FILE       * yyin;
+extern PROGRAMMER * current_prog;
+extern AVRPART    * current_part;
+extern int          current_mem;
+extern LISTID       programmers;
+extern LISTID       part_list;
+extern int          lineno;
+extern char       * infile;
+extern LISTID       string_list;
+extern LISTID       number_list;
+
+#if 0
+#define YYSTYPE struct token_t *
+#endif
+extern YYSTYPE yylval;
+
+extern char string_buf[MAX_STR_CONST];
+extern char *string_buf_ptr;
+
+int yyparse(void);
+
+
+int init_config(void);
+
+TOKEN * new_token(int primary);
+
+void free_token(TOKEN * tkn);
+
+void free_tokens(int n, ...);
+
+TOKEN * number(char * text);
+
+TOKEN * hexnumber(char * text);
+
+TOKEN * string(char * text);
+
+TOKEN * id(char * text);
+
+TOKEN * keyword(int primary);
+
+void print_token(TOKEN * tkn);
+
+PROGRAMMER * new_programmer(void);
+
+AVRPART * new_part(void);
+
+AVRPART * dup_part(AVRPART * d);
+
+char * dup_string(char * str);
+
+#endif
diff --git a/avrdude/config_gram.y b/avrdude/config_gram.y
new file mode 100644
index 00000000..f32d10f0
--- /dev/null
+++ b/avrdude/config_gram.y
@@ -0,0 +1,307 @@
+/* $Id$ */
+
+%token K_BANK_SIZE
+%token K_BANKED
+%token K_BUFF
+%token K_CHIP_ERASE_DELAY
+%token K_DESC
+%token K_EEPROM
+%token K_ERRLED
+%token K_FLASH
+%token K_ID
+%token K_MAX_WRITE_DELAY
+%token K_MIN_WRITE_DELAY
+%token K_MISO
+%token K_MOSI
+%token K_NO
+%token K_NUM_BANKS
+%token K_PART
+%token K_PGMLED
+%token K_PROGRAMMER
+%token K_RDYLED
+%token K_READBACK_P1
+%token K_READBACK_P2
+%token K_RESET
+%token K_SCK
+%token K_SIZE
+%token K_VCC
+%token K_VFYLED
+%token K_YES
+
+%token TKN_COMMA
+%token TKN_EQUAL
+%token TKN_SEMI
+%token TKN_NUMBER
+%token TKN_STRING
+%token TKN_ID
+
+%start config
+
+%%
+
+
+config :
+  def |
+  config def
+;
+
+
+def :
+  prog_def TKN_SEMI |
+  part_def TKN_SEMI
+;
+
+
+prog_def :
+  K_PROGRAMMER 
+    { current_prog = new_programmer(); }
+    prog_parms
+    { 
+      if (lsize(current_prog->id) == 0) {
+        fprintf(stderr,
+                "%s: error at %s:%d: required parameter id not specified\n",
+                progname, infile, lineno);
+        exit(1);
+      }
+      ladd(programmers, current_prog); 
+      current_prog = NULL; 
+    }
+;
+
+
+part_def :
+  K_PART
+    { current_part = avr_new_part(); }
+    part_parms
+    { 
+      if (current_part->id[0] == 0) {
+        fprintf(stderr,
+                "%s: error at %s:%d: required parameter id not specified\n",
+                progname, infile, lineno);
+        exit(1);
+      }
+      ladd(part_list, current_part); 
+      current_part = NULL; 
+    }
+;
+
+
+string_list :
+  TKN_STRING { ladd(string_list, $1); } |
+  string_list TKN_COMMA TKN_STRING { ladd(string_list, $3); }
+;
+
+
+num_list :
+  TKN_NUMBER { ladd(number_list, $1); } |
+  num_list TKN_COMMA TKN_NUMBER { ladd(number_list, $3); }
+;
+
+
+prog_parms :
+  prog_parm TKN_SEMI |
+  prog_parms prog_parm TKN_SEMI
+;
+
+
+prog_parm :
+  K_ID TKN_EQUAL string_list {
+    { 
+      TOKEN * t;
+      while (lsize(string_list)) {
+        t = lrmv_n(string_list, 1);
+        ladd(current_prog->id, dup_string(t->value.string));
+        free_token(t);
+      }
+    }
+  } |
+
+  K_DESC TKN_EQUAL TKN_STRING {
+    strncpy(current_prog->desc, $3->value.string, PGM_DESCLEN);
+    current_prog->desc[PGM_DESCLEN-1] = 0;
+    free_token($3);
+  } |
+
+  K_VCC TKN_EQUAL num_list {
+    { 
+      TOKEN * t;
+      int pin;
+
+      current_prog->pinno[PPI_AVR_VCC] = 0;
+
+      while (lsize(number_list)) {
+        t = lrmv_n(number_list, 1);
+        pin = t->value.number;
+        if ((pin < 2) || (pin > 9)) {
+          fprintf(stderr, 
+                  "%s: error at line %d of %s: VCC must be one or more "
+                  "pins from the range 2-9\n",
+                  progname, lineno, infile);
+          exit(1);
+        }
+
+        current_prog->pinno[PPI_AVR_VCC] |= (1 << (pin-2));
+
+        free_token(t);
+      }
+    }
+  } |
+
+  K_RESET  TKN_EQUAL TKN_NUMBER { assign_pin(PIN_AVR_RESET, $3); } |
+  K_SCK    TKN_EQUAL TKN_NUMBER { assign_pin(PIN_AVR_SCK, $3); } |
+  K_MOSI   TKN_EQUAL TKN_NUMBER { assign_pin(PIN_AVR_MOSI, $3); } |
+  K_MISO   TKN_EQUAL TKN_NUMBER { assign_pin(PIN_AVR_MISO, $3); } |
+  K_BUFF   TKN_EQUAL TKN_NUMBER { assign_pin(PIN_AVR_BUFF, $3); } |
+  K_ERRLED TKN_EQUAL TKN_NUMBER { assign_pin(PIN_LED_ERR, $3); } |
+  K_RDYLED TKN_EQUAL TKN_NUMBER { assign_pin(PIN_LED_RDY, $3); } |
+  K_PGMLED TKN_EQUAL TKN_NUMBER { assign_pin(PIN_LED_PGM, $3); } |
+  K_VFYLED TKN_EQUAL TKN_NUMBER { assign_pin(PIN_LED_VFY, $3); }
+;
+
+
+part_parms :
+  part_parm TKN_SEMI |
+  part_parms part_parm TKN_SEMI
+;
+
+
+part_parm :
+  K_ID TKN_EQUAL TKN_STRING 
+    {
+      strncpy(current_part->id, $3->value.string, AVR_IDLEN);
+      current_part->id[AVR_IDLEN-1] = 0;
+      free_token($3);
+    } |
+
+  K_DESC TKN_EQUAL TKN_STRING 
+    {
+      strncpy(current_part->desc, $3->value.string, AVR_DESCLEN);
+      current_part->desc[AVR_DESCLEN-1] = 0;
+      free_token($3);
+    } |
+
+  K_CHIP_ERASE_DELAY TKN_EQUAL TKN_NUMBER
+    {
+      current_part->chip_erase_delay = $3->value.number;
+      free_token($3);
+    } |
+
+  K_EEPROM { current_mem = AVR_M_EEPROM; }
+    mem_specs |
+
+  K_FLASH { current_mem = AVR_M_FLASH; }
+    mem_specs
+;
+
+
+yesno :
+  K_YES | K_NO
+;
+
+
+mem_specs :
+  mem_spec TKN_SEMI |
+  mem_specs mem_spec TKN_SEMI
+;
+
+
+mem_spec :
+  K_BANKED          TKN_EQUAL yesno
+    {
+      current_part->mem[current_mem].banked = $3->primary == K_YES ? 1 : 0;
+      free_token($3);
+    } |
+
+  K_SIZE            TKN_EQUAL TKN_NUMBER
+    {
+      current_part->mem[current_mem].size = $3->value.number;
+      free_token($3);
+    } |
+
+
+  K_BANK_SIZE       TKN_EQUAL TKN_NUMBER
+    {
+      current_part->mem[current_mem].bank_size = $3->value.number;
+      free_token($3);
+    } |
+
+  K_NUM_BANKS       TKN_EQUAL TKN_NUMBER
+    {
+      current_part->mem[current_mem].num_banks = $3->value.number;
+      free_token($3);
+    } |
+
+  K_MIN_WRITE_DELAY TKN_EQUAL TKN_NUMBER
+    {
+      current_part->mem[current_mem].min_write_delay = $3->value.number;
+      free_token($3);
+    } |
+
+  K_MAX_WRITE_DELAY TKN_EQUAL TKN_NUMBER
+    {
+      current_part->mem[current_mem].max_write_delay = $3->value.number;
+      free_token($3);
+    } |
+
+  K_READBACK_P1     TKN_EQUAL TKN_NUMBER
+    {
+      current_part->mem[current_mem].readback[0] = $3->value.number;
+      free_token($3);
+    } |
+
+  K_READBACK_P2     TKN_EQUAL TKN_NUMBER
+    {
+      current_part->mem[current_mem].readback[1] = $3->value.number;
+      free_token($3);
+    }
+;
+
+
+%%
+
+#include <string.h>
+#include <math.h>
+
+#include "config.h"
+#include "lists.h"
+#include "pindefs.h"
+#include "avr.h"
+
+extern char * progname;
+
+int yylex(void);
+int yyerror(char * errmsg);
+
+
+#if 0
+static char * vtypestr(int type)
+{
+  switch (type) {
+    case V_NUM : return "NUMERIC";
+    case V_STR : return "STRING";
+    default:
+      return "<UNKNOWN>";
+  }
+}
+#endif
+
+
+static int assign_pin(int pinno, TOKEN * v)
+{
+  int value;
+
+  value = v->value.number;
+
+  if ((value <= 0) || (value >= 18)) {
+    fprintf(stderr, 
+            "%s: error at line %d of %s: pin must be in the "
+            "range 1-17\n",
+            progname, lineno, infile);
+    exit(1);
+  }
+
+  current_prog->pinno[pinno] = value;
+
+  return 0;
+}
+
diff --git a/avrdude/lexer.l b/avrdude/lexer.l
new file mode 100644
index 00000000..60e75a20
--- /dev/null
+++ b/avrdude/lexer.l
@@ -0,0 +1,137 @@
+/* $Id$ */
+
+%{
+/* need this for the call to atof() below */
+#include <math.h>
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "config.h"
+#include "y.tab.h"
+#include "lists.h"
+
+extern int    lineno;
+extern char * infile;
+
+void pyytext(void);
+
+%}
+
+DIGIT    [0-9]
+HEXDIGIT [0-9a-fA-F]
+ID       [_a-zA-Z][_a-zA-Z0-9]*
+SIGN     [+-]
+
+%x str
+%x incl
+%x comment
+
+%%
+
+{SIGN}*{DIGIT}+            { yylval = number(yytext); return TKN_NUMBER; }
+{SIGN}*{DIGIT}+"."{DIGIT}* { yylval = number(yytext); return TKN_NUMBER; }
+{SIGN}*"."{DIGIT}*         { yylval = number(yytext); return TKN_NUMBER; }
+
+"\""      { string_buf_ptr = string_buf; BEGIN(str); }
+
+0x{HEXDIGIT}+ { yylval = hexnumber(yytext); return TKN_NUMBER; }
+
+
+
+#   { /* The following eats '#' style comments to end of line */
+       BEGIN(comment); }
+<comment>[^\n] /* eat comments */ 
+<comment>\n { lineno++; BEGIN(INITIAL); }
+
+
+"/*" {  /* The following eats multiline C style comments */
+        int c;
+        int comment_start;
+        
+        comment_start = lineno;
+        while (1) {
+          while (((c = input()) != '*') && (c != EOF)) {
+            /* eat up text of comment, but keep counting lines */
+            if (c == '\n')
+              lineno++;
+          }
+          
+          if (c == '*') {
+            while ((c = input()) == '*')
+              ;
+            if (c == '/')
+              break;    /* found the end */
+          }
+          
+          if (c == EOF) {
+            fprintf(stderr, "error at %s:%d: EOF in comment\n", 
+                    infile, lineno);
+            fprintf(stderr, "    comment started on line %d\n", 
+                    comment_start);
+            exit(1);
+            break;
+          }
+        }
+     }
+
+
+<str>{
+  \" { *string_buf_ptr = 0; string_buf_ptr = string_buf; 
+         yylval = string(string_buf_ptr); BEGIN(INITIAL); return TKN_STRING; }
+  \\n  *string_buf_ptr++ = '\n';
+  \\t  *string_buf_ptr++ = '\t';
+  \\r  *string_buf_ptr++ = '\r';
+  \\b  *string_buf_ptr++ = '\b';
+  \\f  *string_buf_ptr++ = '\f';
+  \\(.|\n)  *(string_buf_ptr++) = yytext[1];
+  [^\\\n\"]+ { char *yptr = yytext; while (*yptr) 
+                                         *(string_buf_ptr++) = *(yptr++); }
+  \n { fprintf(stderr, "error at line %d: unterminated character constant\n",
+         lineno); 
+         exit(1); }
+}
+
+bank_size        { yylval=NULL; return K_BANK_SIZE; }
+banked           { yylval=NULL; return K_BANKED; }
+buff             { yylval=NULL; return K_BUFF; }
+chip_erase_delay { yylval=NULL; return K_CHIP_ERASE_DELAY; }
+desc             { yylval=NULL; return K_DESC; }
+eeprom           { yylval=NULL; return K_EEPROM; }
+errled           { yylval=NULL; return K_ERRLED; }
+flash            { yylval=NULL; return K_FLASH; }
+id               { yylval=NULL; return K_ID; }
+max_write_delay  { yylval=NULL; return K_MAX_WRITE_DELAY; }
+min_write_delay  { yylval=NULL; return K_MIN_WRITE_DELAY; }
+miso             { yylval=NULL; return K_MISO; }
+mosi             { yylval=NULL; return K_MOSI; }
+num_banks        { yylval=NULL; return K_NUM_BANKS; }
+part             { yylval=NULL; return K_PART; }
+pgmled           { yylval=NULL; return K_PGMLED; }
+programmer       { yylval=NULL; return K_PROGRAMMER; }
+rdyled           { yylval=NULL; return K_RDYLED; }
+readback_p1      { yylval=NULL; return K_READBACK_P1; }
+readback_p2      { yylval=NULL; return K_READBACK_P2; }
+reset            { yylval=NULL; return K_RESET; }
+sck              { yylval=NULL; return K_SCK; }
+size             { yylval=NULL; return K_SIZE; }
+vcc              { yylval=NULL; return K_VCC; }
+vfyled           { yylval=NULL; return K_VFYLED; }
+
+no               { yylval=new_token(K_NO); return K_NO; }
+yes              { yylval=new_token(K_YES); return K_YES; }
+
+","       { yylval = NULL; pyytext(); return TKN_COMMA; }
+"="       { yylval = NULL; pyytext(); return TKN_EQUAL; }
+";"       { yylval = NULL; pyytext(); return TKN_SEMI; }
+
+"\n"      { lineno++; }
+[ \t]+  /* ignore whitespace */
+
+. { fprintf(stderr, "error at %s:%d unrecognized character: \"%s\"\n", 
+            infile, lineno, yytext); exit(1); }
+
+%%
+
diff --git a/avrdude/lists.c b/avrdude/lists.c
new file mode 100644
index 00000000..b355096b
--- /dev/null
+++ b/avrdude/lists.c
@@ -0,0 +1,1355 @@
+ /* $Id$ */
+
+
+/*----------------------------------------------------------------------
+  Id: lists.c,v 1.4 2001/08/19 23:26:20 bsd Exp $
+  ----------------------------------------------------------------------*/
+/*------------------------------------------------------------------------
+  lists.c
+
+  General purpose linked list routines.  These routines implement a
+  generic doubly linked list.  Any data type may be placed in the
+  lists.  Stacking and Queuing routines are provided via #defines
+  declared in 'lists.h'.
+
+  Author : Brian Dean
+  Date   : 10 January, 1990
+  ------------------------------------------------------------------------*/
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "lists.h"
+
+char * lists_version = "$Id$";
+
+#define MAGIC 0xb05b05b0
+
+#define CHECK_MAGIC 0 /* set to 1 to enable memory overwrite detection */
+
+#ifdef BOS
+#define MALLOC(size,x) kmalloc(size,x)
+#define FREE           kfree
+#else
+#define MALLOC(size,x) malloc(size)
+#define FREE           free
+#endif
+
+
+/*------------------------------------------------------------
+|  required private data structures
+ ------------------------------------------------------------*/
+typedef struct LISTNODE {
+#if CHECK_MAGIC
+  unsigned int      magic1;
+#endif
+  struct LISTNODE * next; /* chain to next item in the list */
+  struct LISTNODE * prev; /* chain to previous item in the list */
+  void            * data; /* pointer to user data */
+#if CHECK_MAGIC
+  unsigned int      magic2;
+#endif
+} LISTNODE;
+
+
+typedef struct NODEPOOL {
+#if CHECK_MAGIC
+  unsigned int      magic1;
+#endif
+  struct NODEPOOL * chain_next;  /* chain to next node pool */
+  struct NODEPOOL * chain_prev;  /* chain to previous node pool */
+#if CHECK_MAGIC
+  unsigned int      magic2;
+#endif
+} NODEPOOL;
+
+
+typedef struct LIST {
+#if CHECK_MAGIC
+  unsigned int magic1;
+#endif
+  int        num;           /* number of elements in the list    */
+  short int  free_on_close; /* free the LIST memory on close T/F */
+  short int  poolsize;      /* list node allocation size         */
+  int        n_ln_pool;     /* number of listnodes in a pool     */
+  LISTNODE * top;           /* top of the list                   */
+  LISTNODE * bottom;        /* bottom of the list                */
+  LISTNODE * next_ln;       /* next available list node          */
+  NODEPOOL * np_top;        /* top of the node pool chain        */
+  NODEPOOL * np_bottom;     /* bottom of the node pool chain     */
+#if CHECK_MAGIC
+  unsigned int magic2;
+#endif
+} LIST;
+
+
+/* allocate list nodes in 512 byte chunks, giving 42 elements */
+#define DEFAULT_POOLSIZE 512
+
+
+#if CHECK_MAGIC
+#define CKMAGIC(p) { if (p->magic1 != MAGIC) breakpoint(); \
+                     if (p->magic2 != MAGIC) breakpoint(); }
+
+#define CKNPMAGIC(p) cknpmagic(p)
+
+#define CKLNMAGIC(p) cklnmagic(p)
+
+#define CKLMAGIC(p)  cklmagic(p)
+#else
+#define CKMAGIC(p)
+
+#define CKNPMAGIC(p)
+
+#define CKLNMAGIC(p)
+
+#define CKLMAGIC(p)
+#endif
+
+
+static int insert_ln ( LIST * l, LISTNODE * ln, void * data_ptr );
+
+
+#if CHECK_MAGIC
+static int cknpmagic ( LIST * l )
+{
+  NODEPOOL * np;
+  int i;
+
+  i = 0;
+  np = l->np_top;
+  while (np) {
+    i++;
+    CKMAGIC(np);
+    np = np->chain_next;
+  }
+
+  i = 0;
+  np = l->np_bottom;
+  while (np) {
+    i++;
+    CKMAGIC(np);
+    np = np->chain_prev;
+  }
+
+  return 0;
+}
+
+
+
+static int cklnmagic ( LIST * l )
+{
+  LISTNODE * ln;
+  int i;
+
+  i = 0;
+  ln = l->top;
+  while (ln) {
+    i++;
+    CKMAGIC(ln);
+    ln = ln->next;
+  }
+
+  i = 0;
+  ln = l->bottom;
+  while (ln) {
+    i++;
+    CKMAGIC(ln);
+    ln = ln->prev;
+  }
+
+  return 0;
+}
+
+
+static int cklmagic ( LIST * l )
+{
+  CKMAGIC(l);
+  CKNPMAGIC(l);
+  CKLNMAGIC(l);
+  CKMAGIC(l);
+  return 0;
+}
+#endif
+
+
+/*------------------------------------------------------------
+|  new_node_pool
+|
+|  Create and initialize a new pool of list nodes.  This is
+|  just a big block of memory with the first sizeof(NODEPOOL)
+|  bytes reserved.  The first available list node resides at
+|  offset sizeof(NODEPOOL).
+ ------------------------------------------------------------*/
+static
+NODEPOOL * 
+new_nodepool ( LIST * l )
+{
+  NODEPOOL * np;
+  LISTNODE * ln;
+  int i;
+
+  CKLMAGIC(l);
+
+  /*--------------------------------------------------
+  |  get a block of memory for the new pool
+   --------------------------------------------------*/
+  np = (NODEPOOL *) MALLOC ( l->poolsize, "list node pool" );
+  if (np == NULL) {
+    return NULL;
+  }
+
+  /*--------------------------------------------------
+  |  initialize the chaining information at the
+  |  beginning of the pool.
+   --------------------------------------------------*/
+#if CHECK_MAGIC
+  np->magic1 = MAGIC;
+#endif
+  np->chain_next = NULL;
+  np->chain_prev = NULL;
+#if CHECK_MAGIC
+  np->magic2 = MAGIC;
+#endif
+
+  /*--------------------------------------------------
+  |  initialize all the list nodes within the node
+  |  pool, which begin just after the NODEPOOL
+  |  structure at the beginning of the memory block
+   --------------------------------------------------*/
+  ln = (LISTNODE *) (&np[1]);
+
+#if CHECK_MAGIC
+  ln[0].magic1 = MAGIC;
+#endif
+  ln[0].data = NULL;
+  ln[0].next = &ln[1];
+  ln[0].prev = NULL;
+#if CHECK_MAGIC
+  ln[0].magic2 = MAGIC;
+#endif
+
+  for (i=1; i<l->n_ln_pool-1; i++) {
+#if CHECK_MAGIC
+    ln[i].magic1 = MAGIC;
+#endif
+    ln[i].data = NULL;
+    ln[i].next = &ln[i+1];
+    ln[i].prev = &ln[i-1];
+#if CHECK_MAGIC
+    ln[i].magic2 = MAGIC;
+#endif
+  }
+
+#if CHECK_MAGIC
+  ln[l->n_ln_pool-1].magic1 = MAGIC;
+#endif
+  ln[l->n_ln_pool-1].data = NULL;
+  ln[l->n_ln_pool-1].next = NULL;
+  ln[l->n_ln_pool-1].prev = &ln[l->n_ln_pool-2];
+#if CHECK_MAGIC
+  ln[l->n_ln_pool-1].magic2 = MAGIC;
+#endif
+
+  CKMAGIC(np);
+
+  CKLMAGIC(l);
+
+  return np;
+}
+
+
+
+/*------------------------------------------------------------
+|  get_listnode
+|
+|  Get the next available list node.  If there are no more
+|  list nodes, another pool of list nodes is allocated.  If
+|  that fails, NULL is returned.
+ ------------------------------------------------------------*/
+static
+LISTNODE * 
+get_listnode ( LIST * l )
+{
+  LISTNODE * ln;
+  NODEPOOL * np;
+
+  CKLMAGIC(l);
+
+  if (l->next_ln == NULL) {
+    /*--------------------------------------------------
+    | allocate a new node pool and chain to the others
+     --------------------------------------------------*/
+    np = new_nodepool(l);
+    if (np == NULL) {
+      CKLMAGIC(l);
+      return NULL;
+    }
+
+    if (l->np_top == NULL) {
+      /*--------------------------------------------------
+      |  this is the first node pool for this list,
+      |  directly assign to the top and bottom.
+       --------------------------------------------------*/
+      l->np_top = np;
+      l->np_bottom = np;
+      np->chain_next = NULL;
+      np->chain_prev = NULL;
+    }
+    else {
+      /*--------------------------------------------------
+      |  this is an additional node pool, add it to the
+      |  chain.
+       --------------------------------------------------*/
+      np->chain_next = NULL;
+      np->chain_prev = l->np_bottom;
+      l->np_bottom->chain_next = np;
+      l->np_bottom = np;
+    }
+
+    /*--------------------------------------------------
+    |  set the list's pointer to the next available
+    |  list node to the first list node in this new
+    |  pool.
+     --------------------------------------------------*/
+    l->next_ln = (LISTNODE *)&np[1];
+
+    CKMAGIC(np);
+  }
+
+  /*--------------------------------------------------
+  |  get the next available list node, set the list's
+  |  next available list node to the next one in the
+  |  list.
+   --------------------------------------------------*/
+  ln = l->next_ln;
+  l->next_ln = ln->next;
+
+  CKMAGIC(ln);
+
+  /*--------------------------------------------------
+  |  initialize the new list node and return
+   --------------------------------------------------*/
+  ln->next = NULL;
+  ln->prev = NULL;
+  ln->data = NULL;
+
+  CKLMAGIC(l);
+
+  return ln;
+}
+
+
+
+/*------------------------------------------------------------
+|  free_listnode
+|
+|  Return a list node to the pool of list nodes.  This puts
+|  the node at the head of the free list, so that the next
+|  call to 'get_listnode', with return the most recently
+|  freed one.
+ ------------------------------------------------------------*/
+static
+int 
+free_listnode ( LIST * l, LISTNODE * ln )
+{
+  CKLMAGIC(l);
+
+  /*--------------------------------------------------
+  |  insert the list node at the head of the list of
+  |  free list nodes.
+   --------------------------------------------------*/
+  ln->prev = NULL;
+  ln->data = NULL;
+  ln->next = l->next_ln;
+  l->next_ln = ln;
+
+  CKLMAGIC(l);
+
+  return 0;
+}
+
+
+
+/*----------------------------------------------------------------------
+  lcreat
+
+  Create a new list data structure.  
+  
+  If liststruct is not NULL, it is used to provide the memory space
+  for the list structure instance, otherwise, the necessary memory is
+  malloc'd.
+
+  If elements is zero, the default poolsize is used, otherwise,
+  poolsizes of 'elements' elements are malloc'd to obtain the memory
+  for list nodes.  Minimum element count is 5.
+
+  The first node pool is not preallocated; instead it is malloc'd at
+  the time of the first use.
+  ----------------------------------------------------------------------*/
+LISTID
+lcreat ( void * liststruct, int elements )
+{
+  LIST * l;
+
+  if (LISTSZ != sizeof(LIST)) {
+    printf ( "lcreat(): warning, LISTSZ[%d] != sizeof(LIST)[%d]\n",
+             LISTSZ, sizeof(LIST) );
+  }
+
+  if (liststruct == NULL) {
+    /*--------------------------------------------------
+      allocate memory for the list itself
+      --------------------------------------------------*/
+    l = (LIST *) MALLOC ( sizeof(LIST), "list struct" );
+    if (l == NULL) {
+      return NULL;
+    }
+    l->free_on_close = 1;
+  }
+  else {
+    /*-----------------------------------------------------------------
+      use the memory given to us for the list structure
+      -----------------------------------------------------------------*/
+    l = liststruct;
+    l->free_on_close = 0;
+  }
+
+  /*--------------------------------------------------
+  |  initialize the list
+   --------------------------------------------------*/
+#if CHECK_MAGIC
+  l->magic1 = MAGIC;
+  l->magic2 = MAGIC;
+#endif
+  l->top = NULL;
+  l->bottom = NULL;
+  l->num = 0;
+
+  if (elements == 0) {
+    l->poolsize = DEFAULT_POOLSIZE;
+  }
+  else {
+    l->poolsize = elements*sizeof(LISTNODE)+sizeof(NODEPOOL);
+  }
+
+  l->n_ln_pool = (l->poolsize-sizeof(NODEPOOL))/sizeof(LISTNODE);
+
+  if (l->n_ln_pool < 5) {
+    if (!liststruct) {
+      FREE(l);
+    }
+    return NULL;
+  }
+
+  l->np_top = NULL;
+  l->np_bottom = NULL;
+  l->next_ln = NULL;
+
+  CKLMAGIC(l);
+
+  return (LISTID)l;
+}
+
+
+/*--------------------------------------------------
+|  ldestroy_cb
+|
+|  destroy an existing list data structure, calling
+|  the user routine 'ucleanup' on the data pointer
+|  of each list element.  Allows the user to free
+|  up a list data structure and have this routine
+|  call their function to free up each list element
+|  at the same time.
+ --------------------------------------------------*/
+void 
+ldestroy_cb ( LISTID lid, void (*ucleanup)() )
+{
+  LIST * l;
+  LISTNODE * ln;
+
+  l = (LIST *)lid;
+
+  CKLMAGIC(l);
+
+  ln = l->top;
+  while (ln != NULL) {
+    ucleanup ( ln->data );
+    ln = ln->next;
+  }
+
+  ldestroy ( l );
+}
+
+
+
+/*--------------------------------------------------
+|  ldestroy
+|
+|  destroy an existing list data structure.
+|
+|  assumes that each data element does not need to
+|  be freed.
+ --------------------------------------------------*/
+void 
+ldestroy ( LISTID lid )
+{
+  LIST * l;
+  NODEPOOL * p1, * p2;
+
+  l = (LIST *)lid;
+
+  CKLMAGIC(l);
+
+  /*--------------------------------------------------
+  |  free each node pool - start at the first node
+  |  pool and free each successive until there are
+  |  no more.
+   --------------------------------------------------*/
+  p1 = l->np_top;
+  while (p1 != NULL) {
+    p2 = p1->chain_next;
+    FREE(p1);
+    p1 = p2;
+  }
+
+  /*--------------------------------------------------
+  |  now free the memory occupied by the list itself
+   --------------------------------------------------*/
+  if (l->free_on_close) {
+    FREE ( l );
+  }
+}
+
+
+
+
+/*------------------------------------------------------------
+|  ladd
+|
+|  add list - add item p to the list
+ ------------------------------------------------------------*/
+int 
+ladd ( LISTID lid, void * p )
+{
+  LIST * l;
+  LISTNODE *lnptr;
+
+  l = (LIST *)lid;
+
+  CKLMAGIC(l);
+
+  lnptr = get_listnode(l);
+  if (lnptr==NULL) {
+#ifdef BOS
+    breakpoint();
+#endif
+    return -1;
+  }
+
+  CKMAGIC(lnptr);
+
+  lnptr->data = p;
+
+  if (l->top == NULL) {
+    l->top = lnptr;
+    l->bottom = lnptr;
+    lnptr->next = NULL;
+    lnptr->prev = NULL;
+  }
+  else {
+    lnptr->prev = l->bottom;
+    lnptr->next = NULL;
+    l->bottom->next = lnptr;
+    l->bottom = lnptr;
+  }
+  l->num++;
+
+  CKLMAGIC(l);
+
+  return 0;
+}
+
+
+
+/*------------------------------------------------------------
+|  laddo
+|
+|  add list, ordered - add item p to the list, use 'compare'
+|  function to place 'p' when the comparison 'p' is less than
+|  the next item.  Return 0 if this was a unique entry,
+|  else return 1 indicating a duplicate entry, i.e., the
+|  compare function returned 0 while inserting the element.
+ ------------------------------------------------------------*/
+int 
+laddo ( LISTID lid, void * p, int (*compare)(const void *p1,const void *p2), 
+	LNODEID * firstdup )
+{
+  LIST * l;
+  LISTNODE * ln;
+  int dup, cmp;
+
+  l = (LIST *)lid;
+
+  CKLMAGIC(l);
+
+  dup = 0;
+  ln = l->top;
+
+  while (ln!=NULL) {
+    CKMAGIC(ln);
+    cmp = compare(p,ln->data);
+    if (cmp == 0) {
+      dup = 1;
+      if (firstdup)
+	*firstdup = ln;
+    }
+    if (cmp < 0) {
+      insert_ln(l,ln,p);
+      CKLMAGIC(l);
+      return dup;
+    }
+    else {
+      ln = ln->next;
+    }
+  }
+
+  ladd(l,p);
+
+  CKLMAGIC(l);
+
+  return dup;
+}
+
+
+/*---------------------------------------------------------------------------
+|  laddu
+|
+|  add list, ordered, unique - add item p to the list, use 'compare'
+|  function to place 'p' when the comparison 'p' is less than the next
+|  item.  Return 1 if the item was added, 0 if not.
+|
+ --------------------------------------------------------------------------*/
+int 
+laddu ( LISTID lid, void * p, int (*compare)(const void *p1,const void *p2) )
+{
+  LIST * l;
+  LISTNODE * ln;
+  int cmp;
+
+  l = (LIST *)lid;
+
+  CKLMAGIC(l);
+
+  ln = l->top;
+
+  while (ln!=NULL) {
+    CKMAGIC(ln);
+    cmp = compare(p,ln->data);
+    if (cmp == 0) {
+      CKLMAGIC(l);
+      return 0;
+    }
+    if (cmp < 0) {
+      insert_ln(l,ln,p);
+      CKLMAGIC(l);
+      return 1;
+    }
+    else {
+      ln = ln->next;
+    }
+  }
+
+  ladd(l,p);
+
+  CKLMAGIC(l);
+
+  return 1;
+}
+
+
+
+
+LNODEID 
+lfirst ( LISTID lid )
+{
+  CKLMAGIC(((LIST *)lid));
+  return ((LIST *)lid)->top;
+}
+
+
+LNODEID 
+llast  ( LISTID lid )
+{
+  CKLMAGIC(((LIST *)lid));
+  return ((LIST *)lid)->bottom;
+}
+
+
+LNODEID 
+lnext  ( LNODEID lnid )
+{
+  CKMAGIC(((LISTNODE *)lnid));
+  return ((LISTNODE *)lnid)->next;
+}
+
+
+LNODEID 
+lprev  ( LNODEID lnid )
+{
+  CKMAGIC(((LISTNODE *)lnid));
+  return ((LISTNODE *)lnid)->prev;
+}
+
+
+void * 
+ldata ( LNODEID lnid )
+{
+  CKMAGIC(((LISTNODE *)lnid));
+  return ((LISTNODE *)lnid)->data;
+}
+
+
+
+int
+lsize ( LISTID lid )
+{
+  CKLMAGIC(((LIST *)lid));
+  return ((LIST *)lid)->num;
+}
+
+
+
+/*------------------------------------------------------------
+|  lcat
+|
+|  catenate - catenate l2 to l1, return pointer to l1.
+ ------------------------------------------------------------*/
+LISTID
+lcat ( LISTID lid1, LISTID lid2 )
+{
+  CKLMAGIC(((LIST *)lid1));
+  CKLMAGIC(((LIST *)lid2));
+  while (lsize(lid2)) {
+    ladd ( lid1, lrmv_n(lid2,1) );
+  }
+
+  CKLMAGIC(((LIST *)lid1));
+  CKLMAGIC(((LIST *)lid2));
+
+  return lid1;
+}
+
+
+
+/*----------------------------------------------------------------------
+|  lget
+|
+|  get from list, last item - return pointer to the data of the last
+|  item in the list, non-destructive
+ ----------------------------------------------------------------------*/
+void * 
+lget ( LISTID lid )
+{
+  LIST * l;
+  LISTNODE * p;
+
+  l = (LIST *)lid;
+
+  CKLMAGIC(l);
+
+  p = l->bottom;
+
+  if (p == NULL) {
+    CKLMAGIC(l);
+    return NULL;
+  }
+  else {
+    CKLMAGIC(l);
+    return p->data;
+  }
+}
+
+
+
+/*---------------------------------------------------------------
+|  lget_n
+|
+|  get from list, index - return the nth list item, 
+|  non-destructive
+ ---------------------------------------------------------------*/
+void * 
+lget_n ( LISTID lid, unsigned int n )
+{
+  int i;
+  LIST * l;
+  LISTNODE * ln;
+
+  l = (LIST *)lid;
+
+  CKLMAGIC(l);
+
+  if ((n<1)||(n>lsize(l))) {
+    return NULL;
+  }
+
+  ln = l->top;
+  i = 1;
+  while (ln && (i!=n)) {
+    CKMAGIC(ln);
+    ln = ln->next;
+    i++;
+  }
+
+  if (ln) {
+    CKLMAGIC(l);
+    return ln->data;
+  }
+  else {
+    CKLMAGIC(l);
+    return NULL;
+  }
+}
+
+
+
+/*---------------------------------------------------------------
+|  lget_ln
+|
+|  get from list, listnode - return the nth list item, the
+|  listnode is returned instead of the data, non-destructive
+ ---------------------------------------------------------------*/
+LNODEID
+lget_ln ( LISTID lid, unsigned int n )
+{
+  int i;
+  LIST * l;
+  LISTNODE * ln;
+
+  l = (LIST *)lid;
+
+  CKLMAGIC(l);
+
+  if ((n<1)||(n>lsize(l))) {
+    return NULL;
+  }
+
+  ln = l->top;
+  i = 1;
+  while (i!=n) {
+    CKMAGIC(ln);
+    ln = ln->next;
+    i++;
+  }
+
+  CKLMAGIC(l);
+  return (LNODEID)ln;
+}
+
+
+
+/*----------------------------------------------------------------------
+|  insert_ln
+|
+|  insert data, listnode - insert data just before the list item 
+|  pointed to by 'ln'.
+|
+|  This routine is not intended to be called directly by the user
+|  because the validity of ln is not checked.  This routine is called
+|  by list manipulation routines within this module, in which ln is
+|  known to point to a valid list node.
+ ----------------------------------------------------------------------*/
+static 
+int 
+insert_ln ( LIST * l, LISTNODE * ln, void * data_ptr )
+{
+  LISTNODE * lnptr;
+
+  CKLMAGIC(l);
+
+  if (ln==NULL) {
+    ladd ( l, data_ptr );
+    CKLMAGIC(l);
+    return 0;
+  }
+
+  lnptr = get_listnode(l);
+  if (lnptr == NULL) {
+#ifdef BOS
+    breakpoint();
+#endif
+    return -1;
+  }
+
+  CKMAGIC(lnptr);
+
+  lnptr->data = data_ptr;
+
+  if (ln==l->top) {
+    /*------------------------------
+    |  insert before the list head
+     ------------------------------*/
+    lnptr->next = ln;
+    lnptr->prev = NULL;
+    ln->prev = lnptr;
+    l->top = lnptr;
+  }
+  else if (ln==NULL) {
+    /*-----------------
+    |  list was empty
+     -----------------*/
+    lnptr->next = NULL;
+    lnptr->prev = l->bottom;
+    l->bottom->next = lnptr;
+    l->bottom = lnptr;
+  }
+  else {
+    /*-----------------------------------
+    |  insert in the middle of the list
+     -----------------------------------*/
+    lnptr->next = ln;
+    lnptr->prev = ln->prev;
+    lnptr->next->prev = lnptr;
+    lnptr->prev->next = lnptr;
+  }
+
+  l->num++;
+
+  CKLMAGIC(l);
+
+  return 0;
+}
+
+
+
+/*-----------------------------------------------------------------
+|  lins_n
+|
+|  Insert data before the nth item in the list.
+ -----------------------------------------------------------------*/
+int 
+lins_n ( LISTID lid, void * data_ptr, unsigned int n )
+{
+  int i;
+  LIST * l;
+  LISTNODE * ln;
+
+  l = (LIST *)lid;
+
+  CKLMAGIC(l);
+
+  if ((n<1)||(n>(l->num+1))) {
+    return -1;
+  }
+
+  if (l->num == 0) {
+    return ladd ( lid, data_ptr );
+  }
+
+  /*----------------------------------
+  |  locate the nth item in the list
+   ----------------------------------*/
+  ln = l->top;
+  i = 1;
+  while (ln && (i!=n)) {
+    CKMAGIC(ln);
+    ln = ln->next;
+    i++;
+  }
+
+  if (!ln) {
+    CKLMAGIC(l);
+    return -1;
+  }
+
+  CKLMAGIC(l);
+
+  /*-----------------------------------------
+  |  insert before the nth item in the list
+   -----------------------------------------*/
+  return insert_ln ( l, ln, data_ptr );
+}
+
+
+/*-----------------------------------------------------------------
+|  lins_ln
+|
+|  Insert data before the list node pointed to by ln.
+ -----------------------------------------------------------------*/
+int 
+lins_ln ( LISTID lid, LNODEID lnid, void * data_ptr )
+{
+  LIST * l;
+  LISTNODE * ln;
+  LISTNODE * ln_ptr;
+
+  l = (LIST *)lid;
+  ln = (LISTNODE *)lnid;
+
+  CKLMAGIC(l);
+
+  CKMAGIC(ln);
+
+  /*-----------------------------------------
+  |  validate that ln is indeed in the list
+   -----------------------------------------*/
+  ln_ptr = l->top;
+  while ((ln_ptr!=NULL)&&(ln_ptr!=ln)) {
+    CKMAGIC(ln_ptr);
+    ln_ptr = ln_ptr->next;
+  }
+
+  if (ln_ptr == NULL) {
+    CKLMAGIC(l);
+    return -1;
+  }
+
+  CKLMAGIC(l);
+
+  /*--------------------------------
+  |  insert the data into the list
+   --------------------------------*/
+  return insert_ln ( l, ln, data_ptr );
+}
+
+
+
+/*----------------------------------------------------------------------
+|  remove_ln
+|
+|  Remove the item in the list pointed to by ln.  This routine is not
+|  intended to be called directly by the user because the validity
+|  of ln is not checked.  This routine is called by list manipulation
+|  routines within this module, in which ln is known to point to a
+|  valid list node.
+ ----------------------------------------------------------------------*/
+static
+void * 
+remove_ln ( LIST * l, LISTNODE * ln )
+{
+  void * r;
+
+  CKLMAGIC(l);
+
+  CKMAGIC(ln);
+
+  if (ln==l->top) {
+    /*------------------------------
+    |  remove the head of the list
+     ------------------------------*/
+    l->top = ln->next;
+    if (l->top != NULL) {
+      l->top->prev = NULL;
+    }
+    else {
+      /*----------------------------------------
+      |  this was the only item in the list
+       ----------------------------------------*/
+      l->bottom = NULL;
+    }
+  }
+  else if (ln==l->bottom) {
+    /*------------------------------
+    |  remove the tail of the list
+     ------------------------------*/
+    l->bottom = ln->prev;
+    if (l->bottom != NULL) {
+      l->bottom->next = NULL;
+    }
+  }
+  else {
+    /*-------------------------------------
+    |  remove from the middle of the list
+     -------------------------------------*/
+    ln->prev->next = ln->next;
+    ln->next->prev = ln->prev;
+  }
+
+  /*-----------------------------
+  |  prepare to return the data
+   -----------------------------*/
+  r = ln->data;
+
+  /*-----------------------------------------------
+  |  free the listnode for re-use
+   -----------------------------------------------*/
+  free_listnode(l,ln);
+
+  /*------------------------------------
+  |  adjust the item count of the list
+   ------------------------------------*/
+  l->num--;
+
+  CKLMAGIC(l);
+
+  return r;
+}
+
+
+
+/*-------------------------------------------------------------------------
+|  lrmv_d
+|
+|  remove from list, data - removes the data element from the list,
+|  destructive
+ -------------------------------------------------------------------------*/
+void * 
+lrmv_d ( LISTID lid, void * data_ptr )
+{
+  LIST * l;
+  LISTNODE * ln;
+  int i;
+
+  l = (LIST *)lid;
+
+  CKLMAGIC(l);
+
+  i = 0;
+  ln = l->top;
+  while (ln && (ln->data != data_ptr)) {
+    i++;
+    CKMAGIC(ln);
+    ln = ln->next;
+  }
+
+  if (ln == NULL) {
+    CKLMAGIC(l);
+    return NULL;
+  }
+  else {
+    CKLMAGIC(l);
+    return remove_ln ( l, ln );
+  }
+}
+
+
+
+/*-------------------------------------------------------------------------
+|  lrmv_ln
+|
+|  remove from list, by list node - remove the data element pointed to
+|  by 'ln' from the list, destructive
+ -------------------------------------------------------------------------*/
+void * 
+lrmv_ln ( LISTID lid, LNODEID lnid )
+{
+  LIST * l;
+  LISTNODE * ln;
+  LISTNODE * p;
+
+  l = (LIST *)lid;
+  ln = (LISTNODE *)lnid;
+
+  CKLMAGIC(l);
+
+  CKMAGIC(ln);
+
+  p = l->top;
+  while ((p!=NULL)&&(p!=ln)) {
+    CKMAGIC(p);
+    p = p->next;
+  }
+  
+  if (p==NULL) {
+    CKLMAGIC(l);
+    return NULL;
+  }
+  else {
+    CKLMAGIC(l);
+    return remove_ln ( l, p );
+  }
+}
+
+
+
+/*----------------------------------------------------------------------
+|  lrmv_n
+|
+|  remove from list, by item number - remove the nth element from
+|  the list.
+ ----------------------------------------------------------------------*/
+void * 
+lrmv_n ( LISTID lid, unsigned int n )
+{
+  int i;
+  LIST * l;
+  LISTNODE * ln;
+
+  l = (LIST *)lid;
+
+  CKLMAGIC(l);
+
+  if ((n<1)||(n>l->num)) {
+    return NULL;
+  }
+
+  ln = l->top;
+  i = 1;
+  while (ln && (i!=n)) {
+    CKMAGIC(ln);
+    ln = ln->next;
+    i++;
+  }
+
+  if (ln) {
+    CKLMAGIC(l);
+    return remove_ln ( l, ln );
+  }
+  else {
+    CKLMAGIC(l);
+    return NULL;
+  }
+}
+
+
+/*----------------------------------------------------------------------
+|  lrmv
+|
+|  remove from list, last item - remove the last item from the list,
+|  destructive
+ ----------------------------------------------------------------------*/
+void * 
+lrmv ( LISTID lid )
+{
+  LIST * l;
+  LISTNODE * p;
+
+  l = (LIST *)lid;
+
+  CKLMAGIC(l);
+
+  p = l->bottom;
+
+  if (p == NULL) {
+    CKLMAGIC(l);
+    return NULL;
+  }
+  else {
+    CKLMAGIC(l);
+    return remove_ln ( l, p );
+  }
+}
+
+
+
+/*----------------------------------------------------------------------
+|  lsrch
+|
+|  search list - return data element pointed to by 'p', NULL if not
+|  found
+ ----------------------------------------------------------------------*/
+void * 
+lsrch ( LISTID lid, void * p, int (* compare)(void * p1, void * p2) )
+{
+  LIST * l;
+  LISTNODE * ln;
+
+  l = (LIST *)lid;
+
+  CKLMAGIC(l);
+
+  ln = l->top;
+
+  while (ln!=NULL) {
+    CKMAGIC(ln);
+    if (compare(p,ln->data) == 0) {
+      CKLMAGIC(l);
+      return ln->data;
+    }
+    else {
+      ln = ln->next;
+    }
+  }
+
+  CKLMAGIC(l);
+  return NULL;
+}
+
+
+int lprint ( FILE * f, LISTID lid )
+{
+  LIST * l;
+  LISTNODE * ln;
+  NODEPOOL * np;
+  int count;
+
+  l = (LIST *)lid;
+
+  fprintf ( f, "list id 0x%08x internal data structures:\n", 
+            (unsigned int)lid );
+#if CHECK_MAGIC
+  if ((l->magic1 != MAGIC) || (l->magic2 != MAGIC)) {
+    fprintf ( f, "  *** WARNING: LIST MAGIC IS CORRUPT ***\n" );
+  }
+  fprintf ( f, 
+            "  magic1=0x%08x\n"
+            "  magic2=0x%08x\n",
+            l->magic1, l->magic2 );
+#endif
+  fprintf ( f, "   num f pool n_ln        top     bottom    next_ln     np_top  np_bottom\n" );
+  fprintf ( f, "  ---- - ---- ---- ---------- ---------- ---------- ---------- ----------\n" );
+  fprintf ( f, "  %4d %1d %4d %4d %10p %10p %10p %10p %10p\n",
+            l->num, l->free_on_close, l->poolsize, l->n_ln_pool, 
+            l->top, l->bottom,
+            l->next_ln, l->np_top, l->np_bottom );
+  
+
+  fprintf ( f, 
+            "  node pools:\n"
+            "     idx         np     magic1       next       prev     magic2\n"
+            "    ---- ---------- ---------- ---------- ---------- ----------\n" );
+  count = 0;
+  np = l->np_top;
+  while (np != NULL) {
+    count++;
+    fprintf ( f, "    %4d %10p 0x%08x %10p %10p 0x%08x\n", 
+              count, np, 
+#if CHECK_MAGIC
+              np->magic1, 
+#else
+              0,
+#endif
+              np->chain_next, np->chain_prev, 
+#if CHECK_MAGIC
+              np->magic2
+#else
+              0
+#endif
+      );
+    np = np->chain_next;
+  }
+
+  if (f) {
+    fprintf ( f, 
+              "  list elements:\n"
+              "       n         ln     magic1       next       prev       data     magic2\n"
+              "    ---- ---------- ---------- ---------- ---------- ---------- ----------\n" );
+    count = 0;
+    ln = l->top;
+    while (ln != NULL) {
+      count++;
+      fprintf ( f, "    %4d %10p %10x %10p %10p %10p %10x\n", 
+                count, ln, 
+#if CHECK_MAGIC
+                ln->magic1,
+#else
+                0,
+#endif
+                ln->next, ln->prev, ln->data, 
+#if CHECK_MAGIC
+                ln->magic2
+#else
+                0
+#endif
+        );
+      ln = lnext(ln);
+    }
+    if (count != l->num) {
+      fprintf ( f, 
+                "  *** list count is not correct\n"
+                "  *** list id indicates %d, counted items = %d\n", 
+                l->num, count );
+    }
+  }
+
+  return 0;
+}
diff --git a/avrdude/lists.h b/avrdude/lists.h
new file mode 100644
index 00000000..2217d957
--- /dev/null
+++ b/avrdude/lists.h
@@ -0,0 +1,91 @@
+/* $Id$ */
+
+/*----------------------------------------------------------------------
+  Id: lists.h,v 1.2 2001/08/19 23:13:17 bsd Exp $
+  ----------------------------------------------------------------------*/
+/*----------------------------------------------------------------------
+  General purpose linked list routines - header file declarations.
+
+  Author : Brian Dean
+  Date   : 10 January, 1990
+  ----------------------------------------------------------------------*/
+#ifndef __lists_h__
+#define __lists_h__
+
+#include <stdio.h>
+
+typedef void * LISTID;
+typedef void * LNODEID;
+
+
+/*----------------------------------------------------------------------
+  several defines to access the LIST structure as as stack or a queue
+  --- use for program readability
+  ----------------------------------------------------------------------*/
+#define STACKID LISTID
+#define SNODEID LNODEID
+#define QUEUEID LISTID
+#define QNODEID LNODEID
+
+
+#define PUSH(s,d)    lins_n(s,d,1)   /* push 'd' onto the stack */
+#define POP(s)       lrmv_n(s,1)     /* pop the stack */
+#define LOOKSTACK(s) lget_n(s,1)     /* look at the top of the stack, 
+					but don't pop */
+
+
+#define ENQUEUE(q,d) lins_n(q,d,1)   /* put 'd' on the end of the queue */
+#define DEQUEUE(q)   lrmv(q)         /* remove next item from the front of 
+					the queue */
+#define REQUEUE(q,d) ladd(q,d)       /* re-insert (push) item back on the
+					front of the queue */
+#define LOOKQUEUE(q) lget(q)         /* return next item on the queue, 
+					but don't dequeue */
+#define QUEUELEN(q)  lsize(q)       /* length of the queue */
+
+
+#define LISTADD(l,d) ladd(l,d)       /* add to end of the list */
+#define LISTRMV(l,d) lrmv_d(l,d)     /* remove from end of the list */
+
+
+#define LISTSZ  32  /* size of internal private LIST structure */
+
+
+/* .................... Function Prototypes .................... */
+
+LISTID     lcreat      ( void * liststruct, int poolsize );
+void       ldestroy    ( LISTID lid );
+void       ldestroy_cb ( LISTID lid, void (*ucleanup)() );
+
+LNODEID    lfirst ( LISTID  ); /* head of the list */
+LNODEID    llast  ( LISTID  ); /* tail of the list */
+LNODEID    lnext  ( LNODEID ); /* next item in the list */
+LNODEID    lprev  ( LNODEID ); /* previous item in the list */
+void     * ldata  ( LNODEID ); /* data at the current position */
+int        lsize  ( LISTID  ); /* number of elements in the list */
+
+int        ladd     ( LISTID lid, void * p );
+int        laddo    ( LISTID lid, void *p, 
+		      int (*compare)(const void *p1,const void *p2),
+		      LNODEID * firstdup );
+int        laddu    ( LISTID lid, void * p, 
+		      int (*compare)(const void *p1,const void *p2));
+int        lins_n   ( LISTID lid, void * d, unsigned int n );
+int        lins_ln  ( LISTID lid, LNODEID lnid, void * data_ptr );
+
+void     * lget    ( LISTID lid );
+void     * lget_n  ( LISTID lid, unsigned int n );
+LNODEID    lget_ln ( LISTID lid, unsigned int n );
+
+void     * lrmv    ( LISTID lid );
+void     * lrmv_n  ( LISTID lid, unsigned int n );
+void     * lrmv_ln ( LISTID lid, LNODEID lnid );
+void     * lrmv_d  ( LISTID lid, void * data_ptr );
+
+LISTID     lcat    ( LISTID lid1, LISTID lid2 );
+
+void     * lsrch   ( LISTID lid, void * p, int (*compare)(void *p1,void *p2));
+
+int        lprint  ( FILE * f, LISTID lid );
+
+#endif
diff --git a/avrdude/main.c b/avrdude/main.c
index f4508913..520f47d6 100644
--- a/avrdude/main.c
+++ b/avrdude/main.c
@@ -33,9 +33,8 @@
  * Code to program an Atmel AVR AT90S device using the parallel port.
  *
  * Pin definitions can be changed via a config file.  Below is the
- * default pin configuration.
- *
- * Make the following (minimal) connections:
+ * default pin configuration in the absence of a config definition
+ * which lists "default" as one of its ids.
  *
  *  Parallel Port      Programmer Function
  *  -------------      -----------------------------
@@ -46,8 +45,9 @@
  *       Pin   10  <-  AVR MISO (data out)
  *       Pin   18      Signal Ground
  *
- * Additionally, the following conntections can be made to enable
- * additional features:
+ * Additionally, the following connections can be made to enable
+ * additional features, however, to enable these features use the
+ * pin configuration id "alf" ("-c alf" on the command line):
  *
  *  Parallel Port      Programmer Function
  *  -------------      -----------------------------
@@ -86,6 +86,7 @@
 #include <ctype.h>
 
 #include "avr.h"
+#include "config.h"
 #include "fileio.h"
 #include "pindefs.h"
 #include "ppi.h"
@@ -95,22 +96,26 @@
 #define DEFAULT_PARALLEL "/dev/ppi0"
 
 extern char * avr_version;
+extern char * config_version;
 extern char * fileio_version;
+extern char * lists_version;
 extern char * main_version;
 extern char * ppi_version;
 extern char * term_version;
 
-#define N_MODULES 5
+#define N_MODULES 7
 
-char ** modules[5] = { 
-  &avr_version, 
-  &fileio_version, 
+char ** modules[N_MODULES] = { 
+  &avr_version,
+  &config_version,
+  &fileio_version,
+  &lists_version,
   &main_version, 
   &ppi_version, 
   &term_version 
 };
 
-char * version      = "1.3.0";
+char * version      = "1.4.0";
 
 char * main_version = "$Id$";
 
@@ -119,7 +124,10 @@ char   progbuf[PATH_MAX]; /* temporary buffer of spaces the same
                              length as progname; used for lining up
                              multiline messages */
 
-unsigned int pinno[N_PINS];
+PROGRAMMER * pgm = NULL;
+
+PROGRAMMER compiled_in_pgm;
+
 
 /*
  * usage message
@@ -127,11 +135,12 @@ unsigned int pinno[N_PINS];
 void usage(void)
 {
   fprintf(stderr,
-          "Usage: %s -p partno [-e] [-E exitspec[,exitspec]] [-f format] "
-          "[-F] [-V]\n"
+          "\nUsage: %s -p partno [-e] [-E exitspec[,exitspec]] [-f format] "
+          "[-F]\n"
           "      %s[-i filename] [-m memtype] [-o filename] [-P parallel] "
-          "[-t]\n\n",
-          progname, progbuf);
+          "[-t]\n"
+          "      %s[-c programmer] [-C config-file] [-v [-v]] [-n]\n\n",
+          progname, progbuf, progbuf);
 
 }
 
@@ -145,18 +154,18 @@ int getexitspecs(char *s, int *set, int *clr)
 
   while ((cp = strtok(s, ","))) {
     if (strcmp(cp, "reset") == 0) {
-      *clr |= ppi_getpinmask(pinno[PIN_AVR_RESET]);
+      *clr |= ppi_getpinmask(pgm->pinno[PIN_AVR_RESET]);
     }
     else if (strcmp(cp, "noreset") == 0) {
-      *set |= ppi_getpinmask(pinno[PIN_AVR_RESET]);
+      *set |= ppi_getpinmask(pgm->pinno[PIN_AVR_RESET]);
     }
     else if (strcmp(cp, "vcc") == 0) { 
-      if (pinno[PPI_AVR_VCC])
-        *set |= pinno[PPI_AVR_VCC];
+      if (pgm->pinno[PPI_AVR_VCC])
+        *set |= pgm->pinno[PPI_AVR_VCC];
     }
     else if (strcmp(cp, "novcc") == 0) {
-      if (pinno[PPI_AVR_VCC])
-        *clr |= pinno[PPI_AVR_VCC];
+      if (pgm->pinno[PPI_AVR_VCC])
+        *clr |= pgm->pinno[PPI_AVR_VCC];
     }
     else {
       return -1;
@@ -267,318 +276,26 @@ int print_module_versions(FILE * outf, char * timestamp)
 }
 
 
-#define MAX_LINE_LEN 1024
-#define MAX_PIN_NAME 64
 
-int parse_config(int lineno, char * infile, char * config, char * s, 
-                 unsigned int * pinno, char * desc, int desclen)
-{
-  char pin_name[MAX_PIN_NAME];
-  char * p;
-  int i;
-  int pins;
-  unsigned int value;
-  unsigned int v;
-  char * e;
-
-  pins = 0;
-  p = s;
-
-  while (1) {
-
-    while (*p && isspace(*p))
-      p++;
-
-    if (*p == 0) {
-      if (pins == 0) {
-        fprintf(stderr, 
-                "%s: warning: no pins configured using config entry \"%s\" "
-                "at line %d of %s\n",
-                progname, config, lineno, infile);
-      }
-      return 0;
-    }
-
-    /*
-     * parse the pin name
-     */
-    pin_name[0] = 0;
-    i = 0;
-    while (*p && (i<MAX_PIN_NAME) && !((*p == '=')||isspace(*p))) {
-      pin_name[i++] = *p;
-      p++;
-    }
-
-    if (i == MAX_PIN_NAME) {
-      fprintf(stderr, "%s: pin name too long at line %d of \"%s\"\n",
-              progname, lineno, infile);
-      return -1;
-    }
-    pin_name[i] = 0;
-
-    /* skip over spaces and equals sign */
-    while (*p && (isspace(*p)||(*p == '=')))
-      p++;
-
-    if (strcasecmp(pin_name, "desc") == 0) {
-      i = 0;
-      while (*p && (i<desclen) && (*p != ':')) {
-        desc[i++] = *p;
-        p++;
-      }
-      if (i == desclen) {
-        fprintf(stderr, 
-                "%s: error at line %d of %s: description is too "
-                "long (max = %d chars)\n",
-                progname, lineno, infile, desclen);
-        return -1;
-      }
-      desc[i] = 0;
-    }
-    else {
-      /*
-       * parse pin value
-       */
-      value = 0;
-      while (*p && (*p != ':')) {
-        
-        if (strcasecmp(pin_name, "desc") == 0) {
-          i = 0;
-          while (*p && (i<desclen) && (*p != ':')) {
-            desc[i++] = *p;
-            p++;
-          }
-          if (i == desclen) {
-            fprintf(stderr, 
-                    "%s: error at line %d of %s: description is too "
-                    "long (max = %d chars)\n",
-                    progname, lineno, infile, desclen);
-            return -1;
-          }
-          desc[i] = 0;
-        }
-        else {
-          v = strtoul(p, &e, 0);
-          if (e == p) {
-            fprintf(stderr, 
-                    "%s: can't parse pin value at line %d of \"%s\" "
-                    "starting with \"%s\"\n",
-                    progname, lineno, infile, p);
-            return -1;
-          }
-          
-          if (strcasecmp(pin_name, "VCC")==0) {
-            /*
-             * VCC is a bit mask of pins for the data register, pins 2-9
-             */
-            if ((v < 2) || (v > 9)) {
-              fprintf(stderr, 
-                      "%s: error at line %d of %s: VCC must be one or more "
-                      "pins from the range 2-9\n",
-                      progname, lineno, infile);
-              return -1;
-            }
-            value |= (1 << (v-2));
-          }
-          else {
-            if ((v <= 0) || (v >= 18)) {
-              fprintf(stderr, 
-                      "%s: error at line %d of %s: pin must be in the "
-                      "range 1-17\n",
-                      progname, lineno, infile);
-              return -1;
-            }
-            value = v;
-          }
-          
-          p = e;
-          while (*p && (isspace(*p)||(*p == ',')))
-            p++;
-        }
-        
-        if (strcasecmp(pin_name, "VCC")==0)
-          pinno[PPI_AVR_VCC] = value;
-        else if (strcasecmp(pin_name, "BUFF")==0)
-          pinno[PIN_AVR_BUFF] = value;
-        else if (strcasecmp(pin_name, "RESET")==0)
-          pinno[PIN_AVR_RESET] = value;
-        else if (strcasecmp(pin_name, "SCK")==0)
-          pinno[PIN_AVR_SCK] = value;
-        else if (strcasecmp(pin_name, "MOSI")==0)
-          pinno[PIN_AVR_MOSI] = value;
-        else if (strcasecmp(pin_name, "MISO")==0)
-          pinno[PIN_AVR_MISO] = value;
-        else if (strcasecmp(pin_name, "ERRLED")==0)
-          pinno[PIN_LED_ERR] = value;
-        else if (strcasecmp(pin_name, "RDYLED")==0)
-          pinno[PIN_LED_RDY] = value;
-        else if (strcasecmp(pin_name, "PGMLED")==0)
-          pinno[PIN_LED_PGM] = value;
-        else if (strcasecmp(pin_name, "VFYLED")==0)
-          pinno[PIN_LED_VFY] = value;
-        else {
-          fprintf(stderr, 
-                  "%s: error at line %d of %s: invalid pin name \"%s\"\n",
-                  progname, lineno, infile,  pin_name);
-          return -1;
-        } 
-        
-        pins++;
-      }
-    }
-
-    while (*p && (*p == ':'))
-      p++;
-  }
-
-  return 0;
-}
-
-  
-
-int read_config(char * infile, char * config, unsigned int * pinno, 
-                char * desc, int desclen)
+int read_config(char * file)
 {
   FILE * f;
-  char line[MAX_LINE_LEN];
-  char buf[MAX_LINE_LEN];
-  char configname[MAX_PIN_NAME];
-  int len, lineno, rc, cont;
-  char * p, * q;
-  int i;
 
-  for (i=0; i<N_PINS; i++)
-    pinno[i] = 0;
-
-  f = fopen(infile, "r");
+  f = fopen(file, "r");
   if (f == NULL) {
     fprintf(stderr, "%s: can't open config file \"%s\": %s\n",
             progname, infile, strerror(errno));
     return -1;
   }
 
-  lineno = 0;
-  buf[0] = 0;
-  cont   = 0;
-  while (fgets(line, MAX_LINE_LEN, f) != NULL) {
-    lineno++;
+  infile = file;
+  yyin   = f;
 
-    p = line;
-    while (isspace(*p))
-      p++;
+  yyparse();
 
-    /*
-     * skip empty lines and lines that start with '#'
-     */
-    if ((*p == '#')||(*p == '\n')||(*p == 0))
-      continue;
+  fclose(f);
 
-    len = strlen(p);
-    if (p[len-1] == '\n') {
-      p[len-1] = 0;
-      len--;
-    }
-
-    /*
-     * we're only interested in pin configuration data which begin
-     * with "c:" 
-     */
-    if (((len < 3) || (p[0] != 'c')) && !cont)
-      continue;
-
-
-    /*
-     * skip over the "c:"
-     */
-    if (!cont) {
-      p++;
-      while (*p && isspace(*p))
-        p++;
-
-      if (*p != ':') {
-        fprintf(stderr, "line %d:\n%s\n",
-                lineno, line);
-        for (i=0; i<(p-line); i++) {
-          fprintf(stderr, "-");
-        }
-        fprintf(stderr, "^\n");
-        fprintf(stderr, "error at column %d, line %d of %s: expecting ':'\n",
-                p-line+1, lineno, infile);
-        return -1;
-      }
-      p++;
-      len = strlen(p);
-    }
-
-    cont = 0;
-
-    if (p[len-1] == '\\') {
-      cont = 1;              /* flag that this is a continuation line */
-
-      /* trim trailing white space before continuation character */
-      q = &p[len-2];
-      while (isspace(*q))
-        q--;
-      q++;
-      *q = 0;
-    }
-
-    rc = strlcat(buf, p, MAX_LINE_LEN);
-    if (rc >= MAX_LINE_LEN) {
-      fprintf(stderr, 
-              "%s: buffer length of %d exceed at line %d of \"%s\"\n",
-              progname, MAX_LINE_LEN, lineno, infile);
-      return -2;
-    }
-
-    if (cont)
-      continue;  /* continuation line, keep going */
-
-    /*
-     * read the configuration name from the beginning of the line
-     */
-    p = buf;
-    i = 0;
-    while (*p && (i < MAX_PIN_NAME) && (!(isspace(*p)||(*p == ':')))) {
-      configname[i++] = *p;
-      p++;
-    }
-    if (i == MAX_PIN_NAME) {
-      fprintf(stderr, "%s: configuration name too long at line %d of \"%s\"\n",
-              progname, lineno, infile);
-      return -3;
-    }
-    configname[i] = 0;
-
-    /*
-     * position 'p' to the beginning of the pin information
-     */
-    while (*p && (isspace(*p) || (*p == ':')))
-      p++;
-
-    if (strcasecmp(configname, config) == 0) {
-      strlcpy(desc, "no description", desclen);
-      rc = parse_config(lineno, infile, config, p, pinno, desc, desclen);
-      if (rc) {
-        fprintf(stderr, "%s: error parsing config file \"%s\" at line %d\n",
-                progname, infile, lineno);
-        return -3;
-      }
-
-      return 0;
-    }
-
-    buf[0] = 0;
-  }
-
-  /*
-   * config entry not found
-   */
-
-  fprintf(stderr, "%s: config entry \"%s\" not found in file \"%s\"\n",
-          progname, config, infile);
-
-  return -5;
+  return 0;
 }
 
 
@@ -608,20 +325,20 @@ char * vccpins_str(unsigned int pmask)
 }
 
 
-void pinconfig_display(char * p, char * config, char * desc)
+void pinconfig_display(char * p)
 {
   char vccpins[64];
 
-  if (pinno[PPI_AVR_VCC]) {
+  if (pgm->pinno[PPI_AVR_VCC]) {
     snprintf(vccpins, sizeof(vccpins), " = pins %s", 
-             vccpins_str(pinno[PPI_AVR_VCC]));
+             vccpins_str(pgm->pinno[PPI_AVR_VCC]));
   }
   else {
     vccpins[0] = 0;
   }
 
   fprintf(stderr, "%sProgrammer Pin Configuration: %s (%s)\n", p, 
-          config ? config : "DEFAULT", desc);
+          (char *)ldata(lfirst(pgm->id)), pgm->desc);
 
   fprintf(stderr, 
           "%s  VCC     = 0x%02x %s\n"
@@ -634,32 +351,92 @@ void pinconfig_display(char * p, char * config, char * desc)
           "%s  RDY LED = %d\n"
           "%s  PGM LED = %d\n"
           "%s  VFY LED = %d\n",
-          p, pinno[PPI_AVR_VCC], vccpins,
-          p, pinno[PIN_AVR_BUFF],
-          p, pinno[PIN_AVR_RESET],
-          p, pinno[PIN_AVR_SCK],
-          p, pinno[PIN_AVR_MOSI],
-          p, pinno[PIN_AVR_MISO],
-          p, pinno[PIN_LED_ERR],
-          p, pinno[PIN_LED_RDY],
-          p, pinno[PIN_LED_PGM],
-          p, pinno[PIN_LED_VFY]);
+          p, pgm->pinno[PPI_AVR_VCC], vccpins,
+          p, pgm->pinno[PIN_AVR_BUFF],
+          p, pgm->pinno[PIN_AVR_RESET],
+          p, pgm->pinno[PIN_AVR_SCK],
+          p, pgm->pinno[PIN_AVR_MOSI],
+          p, pgm->pinno[PIN_AVR_MISO],
+          p, pgm->pinno[PIN_LED_ERR],
+          p, pgm->pinno[PIN_LED_RDY],
+          p, pgm->pinno[PIN_LED_PGM],
+          p, pgm->pinno[PIN_LED_VFY]);
 }
 
 
 
 void verify_pin_assigned(int pin, char * desc)
 {
-  if (pinno[pin] == 0) {
+  if (pgm->pinno[pin] == 0) {
     fprintf(stderr, "%s: error: no pin has been assigned for %s\n",
             progname, desc);
     exit(1);
   }
 }
 
-    
 
-#define MAX_DESC_LEN 80
+
+PROGRAMMER * locate_pinconfig(LISTID programmers, char * configid)
+{
+  LNODEID ln1, ln2;
+  PROGRAMMER * p;
+  char * id;
+  int found;
+
+  found = 0;
+
+  for (ln1=lfirst(programmers); ln1 && !found; ln1=lnext(ln1)) {
+    p = ldata(ln1);
+    for (ln2=lfirst(p->id); ln2 && !found; ln2=lnext(ln2)) {
+      id = ldata(ln2);
+      if (strcasecmp(configid, id) == 0)
+        found = 1;
+    }  
+  }
+
+  if (found)
+    return p;
+
+  return NULL;
+}
+
+
+AVRPART * locate_part(LISTID parts, char * partdesc)
+{
+  LNODEID ln1;
+  AVRPART * p;
+  int found;
+
+  found = 0;
+
+  for (ln1=lfirst(parts); ln1 && !found; ln1=lnext(ln1)) {
+    p = ldata(ln1);
+    if ((strcasecmp(partdesc, p->id) == 0) ||
+        (strcasecmp(partdesc, p->desc) == 0))
+      found = 1;
+  }
+
+  if (found)
+    return p;
+
+  return NULL;
+}
+
+
+void list_parts(FILE * f, char * prefix, LISTID parts)
+{
+  LNODEID ln1;
+  AVRPART * p;
+
+  for (ln1=lfirst(parts); ln1; ln1=lnext(ln1)) {
+    p = ldata(ln1);
+    fprintf(f, "%s%s = %s\n", prefix, p->id, p->desc);
+  }
+
+  return;
+}
+
+
 
 /*
  * main routine
@@ -675,15 +452,12 @@ int main(int argc, char * argv [])
   int              len;         /* length for various strings */
   unsigned char    sig[4];      /* AVR signature bytes */
   unsigned char    nulldev[4];  /* 0xff signature bytes for comparison */
-  struct avrpart * p, ap1;      /* which avr part we are programming */
-  struct avrpart * v, ap2;      /* used for verify */
+  struct avrpart * p;           /* which avr part we are programming */
+  struct avrpart * v;           /* used for verify */
   int              readorwrite; /* true if a chip read/write op was selected */
   int              ppidata;	/* cached value of the ppi data register */
   int              vsize=-1;    /* number of bytes to verify */
   char             timestamp[64];
-  char             configfile[PATH_MAX]; /* pin configuration file */
-  char *           pinconfig;
-  char             desc[MAX_DESC_LEN];
 
   /* options / operating mode variables */
   int     memtype;     /* AVR_FLASH or AVR_EEPROM */
@@ -700,8 +474,20 @@ int main(int argc, char * argv [])
   int     ppisetbits;  /* bits to set in ppi data register at exit */
   int     ppiclrbits;  /* bits to clear in ppi data register at exit */
   char  * exitspecs;   /* exit specs string from command line */
-  int     verbose;
+  int     verbose;     /* verbose output */
+  char  * pinconfig;   /* programmer id */
+  char  * partdesc;    /* part id */
+  char    configfile[PATH_MAX]; /* pin configuration file */
 
+  progname = rindex(argv[0],'/');
+  if (progname)
+    progname++;
+  else
+    progname = argv[0];
+
+  init_config();
+
+  partdesc      = NULL;
   readorwrite   = 0;
   parallel      = DEFAULT_PARALLEL;
   outputf       = NULL;
@@ -718,7 +504,8 @@ int main(int argc, char * argv [])
   ppisetbits    = 0;
   ppiclrbits    = 0;
   exitspecs     = NULL;
-  pinconfig     = NULL;
+  pgm           = NULL;
+  pinconfig     = "avrprog"; /* compiled-in default */
   verbose       = 0;
 
   strcpy(configfile, CONFIG_DIR);
@@ -727,30 +514,25 @@ int main(int argc, char * argv [])
     strcat(configfile, "/");
   strcat(configfile, "avrprog.conf");
 
-  for (i=0; i<N_PINS; i++)
-    pinno[i] = 0;
-
   /*
-   * default pin configuration
+   * initialize compiled-in default programmer 
    */
-  pinno[PPI_AVR_VCC]   = 0x0f;  /* ppi pins 2-5, data reg bits 0-3 */
-  pinno[PIN_AVR_BUFF]  =  0;
-  pinno[PIN_AVR_RESET] =  7;
-  pinno[PIN_AVR_SCK]   =  8;
-  pinno[PIN_AVR_MOSI]  =  9;
-  pinno[PIN_AVR_MISO]  = 10;
-  pinno[PIN_LED_ERR]   =  0;
-  pinno[PIN_LED_RDY]   =  0;
-  pinno[PIN_LED_PGM]   =  0;
-  pinno[PIN_LED_VFY]   =  0;
-
-  strcpy(desc, "compiled in default");
-
-  progname = rindex(argv[0],'/');
-  if (progname)
-    progname++;
-  else
-    progname = argv[0];
+  pgm = &compiled_in_pgm;
+  pgm->id = lcreat(NULL, 0);
+  ladd(pgm->id, dup_string("avrprog"));
+  strcpy(pgm->desc, "avrprog compiled-in default");
+  for (i=0; i<N_PINS; i++)
+    pgm->pinno[i] = 0;
+  pgm->pinno[PPI_AVR_VCC]   = 0x0f;  /* ppi pins 2-5, data reg bits 0-3 */
+  pgm->pinno[PIN_AVR_BUFF]  =  0;
+  pgm->pinno[PIN_AVR_RESET] =  7;
+  pgm->pinno[PIN_AVR_SCK]   =  8;
+  pgm->pinno[PIN_AVR_MOSI]  =  9;
+  pgm->pinno[PIN_AVR_MISO]  = 10;
+  pgm->pinno[PIN_LED_ERR]   =  0;
+  pgm->pinno[PIN_LED_RDY]   =  0;
+  pgm->pinno[PIN_LED_PGM]   =  0;
+  pgm->pinno[PIN_LED_VFY]   =  0;
 
   len = strlen(progname) + 2;
   for (i=0; i<len; i++)
@@ -820,15 +602,7 @@ int main(int argc, char * argv [])
         break;
 
       case 'p' : /* specify AVR part */
-        p = avr_find_part(optarg);
-        if (p == NULL) {
-          fprintf(stderr, 
-                  "%s: AVR Part \"%s\" not found.  Valid parts are:\n\n",
-                  progname, optarg);
-          avr_list_parts(stderr,"    ");
-          fprintf(stderr, "\n");
-          return 1;
-        }
+        partdesc = optarg;
         break;
 
       case 'e': /* perform a chip erase */
@@ -920,29 +694,53 @@ int main(int argc, char * argv [])
     }
   }
 
+  rc = read_config(configfile);
+  if (rc) {
+    fprintf(stderr, "%s: error reading \"%s\" configuration from \"%s\"\n",
+            progname, pinconfig, configfile);
+    exit(1);
+  }
 
-  if (p == NULL) {
+  if (strcmp(pinconfig, "avrprog") == 0) {
+    pgm = locate_pinconfig(programmers, "default");
+    if (pgm == NULL) {
+      /* no default config listed, use the compile-in default */
+      pgm = &compiled_in_pgm;
+    }
+  }
+  else {
+    pgm = locate_pinconfig(programmers, pinconfig);
+    if (pgm == NULL) {
+      fprintf(stderr, 
+              "%s: Can't find pin config id \"%s\"\n",
+              progname, pinconfig);
+      fprintf(stderr,"\n");
+      exit(1);
+    }
+  }
+
+  if (partdesc == NULL) {
     fprintf(stderr, 
             "%s: No AVR part has been specified, use \"-p Part\"\n\n"
             "  Valid Parts are:\n\n",
             progname);
-    avr_list_parts(stderr, "    ");
+    list_parts(stderr, "    ", part_list);
     fprintf(stderr,"\n");
-    return 1;
+    exit(1);
   }
 
-  /*
-   * read the parallel port pin configuration to use if requested
-   */
-  if (pinconfig != NULL) {
-    rc = read_config(configfile, pinconfig, pinno, desc, MAX_DESC_LEN);
-    if (rc) {
-      fprintf(stderr, "%s: error reading \"%s\" configuration from \"%s\"\n",
-              progname, pinconfig, configfile);
-      exit(1);
-    }
+
+  p = locate_part(part_list, partdesc);
+  if (p == NULL) {
+    fprintf(stderr, 
+            "%s: AVR Part \"%s\" not found.  Valid parts are:\n\n",
+            progname, partdesc);
+    list_parts(stderr, "    ", part_list);
+    fprintf(stderr, "\n");
+    exit(1);
   }
 
+
   if (exitspecs != NULL) {
     if (getexitspecs(exitspecs, &ppisetbits, &ppiclrbits) < 0) {
       usage();
@@ -956,19 +754,13 @@ int main(int argc, char * argv [])
    * programming, one for use in verifying.  These are separate
    * because they need separate flash and eeprom buffer space 
    */
-  ap1 = *p;
-  v   = p;
-  p   = &ap1;
-  ap2 = *v;
-  v   = &ap2;
-
-  avr_initmem(p);
-  avr_initmem(v);
+  p = avr_dup_part(p);
+  v = avr_dup_part(p);
 
   if (verbose) {
     avr_display(stderr, p, progbuf);
     fprintf(stderr, "\n");
-    pinconfig_display(progbuf, pinconfig, desc);
+    pinconfig_display(progbuf);
   }
 
   fprintf(stderr, "\n");
@@ -1008,15 +800,15 @@ int main(int argc, char * argv [])
   /* 
    * turn off all the status leds
    */
-  LED_OFF(fd, pinno[PIN_LED_RDY]);
-  LED_OFF(fd, pinno[PIN_LED_ERR]);
-  LED_OFF(fd, pinno[PIN_LED_PGM]);
-  LED_OFF(fd, pinno[PIN_LED_VFY]);
+  LED_OFF(fd, pgm->pinno[PIN_LED_RDY]);
+  LED_OFF(fd, pgm->pinno[PIN_LED_ERR]);
+  LED_OFF(fd, pgm->pinno[PIN_LED_PGM]);
+  LED_OFF(fd, pgm->pinno[PIN_LED_VFY]);
 
   /*
    * enable the 74367 buffer, if connected; this signal is active low
    */
-  ppi_setpin(fd, pinno[PIN_AVR_BUFF], 0);
+  ppi_setpin(fd, pgm->pinno[PIN_AVR_BUFF], 0);
 
   /*
    * initialize the chip in preperation for accepting commands
@@ -1029,7 +821,7 @@ int main(int argc, char * argv [])
   }
 
   /* indicate ready */
-  LED_ON(fd, pinno[PIN_LED_RDY]);
+  LED_ON(fd, pgm->pinno[PIN_LED_RDY]);
 
   fprintf(stderr, 
             "%s: AVR device initialized and ready to accept instructions\n",
@@ -1171,7 +963,7 @@ int main(int argc, char * argv [])
      * verify that the in memory file (p->mem[AVR_M_FLASH|AVR_M_EEPROM])
      * is the same as what is on the chip 
      */
-    LED_ON(fd, pinno[PIN_LED_VFY]);
+    LED_ON(fd, pgm->pinno[PIN_LED_VFY]);
 
     fprintf(stderr, "%s: verifying %s memory against %s:\n", 
             progname, avr_memtstr(memtype), inputf);
@@ -1181,7 +973,7 @@ int main(int argc, char * argv [])
     if (rc < 0) {
       fprintf(stderr, "%s: failed to read all of %s memory, rc=%d\n", 
               progname, avr_memtstr(memtype), rc);
-      LED_ON(fd, pinno[PIN_LED_ERR]);
+      LED_ON(fd, pgm->pinno[PIN_LED_ERR]);
       exitrc = 1;
       goto main_exit;
     }
@@ -1191,7 +983,7 @@ int main(int argc, char * argv [])
     if (rc < 0) {
       fprintf(stderr, "%s: verification error; content mismatch\n", 
               progname);
-      LED_ON(fd, pinno[PIN_LED_ERR]);
+      LED_ON(fd, pgm->pinno[PIN_LED_ERR]);
       exitrc = 1;
       goto main_exit;
     }
@@ -1199,7 +991,7 @@ int main(int argc, char * argv [])
     fprintf(stderr, "%s: %d bytes of %s verified\n", 
             progname, rc, avr_memtstr(memtype));
 
-    LED_OFF(fd, pinno[PIN_LED_VFY]);
+    LED_OFF(fd, pgm->pinno[PIN_LED_VFY]);
   }
 
 
@@ -1217,9 +1009,9 @@ int main(int argc, char * argv [])
   /*
    * disable the 74367 buffer, if connected; this signal is active low 
    */
-  ppi_setpin(fd, pinno[PIN_AVR_BUFF], 1);
+  ppi_setpin(fd, pgm->pinno[PIN_AVR_BUFF], 1);
 
-  LED_OFF(fd, pinno[PIN_LED_RDY]);
+  LED_OFF(fd, pgm->pinno[PIN_LED_RDY]);
 
   close(fd);
 
diff --git a/avrdude/pindefs.h b/avrdude/pindefs.h
index f41e1021..4c102315 100644
--- a/avrdude/pindefs.h
+++ b/avrdude/pindefs.h
@@ -32,7 +32,6 @@
 #ifndef __pindefs_h__
 #define __pindefs_h__
 
-#if 1
 enum {
   PPI_AVR_VCC=1,
   PIN_AVR_BUFF,
@@ -47,21 +46,6 @@ enum {
   N_PINS
 };
 
-extern unsigned int pinno[N_PINS];
-
-#else
-#define PPI_AVR_VCC    0x0f  /* ppi pins 2-5, data reg bits 0-3 */
-#define PIN_AVR_BUFF   6
-#define PIN_AVR_RESET  7
-#define PIN_AVR_SCK    8
-#define PIN_AVR_MOSI   9
-#define PIN_AVR_MISO  10
-#define PIN_LED_ERR    1
-#define PIN_LED_RDY   14
-#define PIN_LED_PGM   16
-#define PIN_LED_VFY   17
-#endif
-
 #define LED_ON(fd,pin)  ppi_setpin(fd,pin,0)
 #define LED_OFF(fd,pin) ppi_setpin(fd,pin,1)
 
diff --git a/avrdude/term.c b/avrdude/term.c
index b258ff3f..b529dcc9 100644
--- a/avrdude/term.c
+++ b/avrdude/term.c
@@ -37,12 +37,14 @@
 #include <readline/history.h>
 
 #include "avr.h"
+#include "config.h"
 #include "pindefs.h"
 #include "ppi.h"
 
 
-extern char * progname;
-extern char   progbuf[];
+extern char       * progname;
+extern char         progbuf[];
+extern PROGRAMMER * pgm;
 
 
 struct command {
@@ -362,7 +364,7 @@ int cmd_write(int fd, struct avrpart * p, int argc, char * argv[])
     }
   }
 
-  LED_OFF(fd, pinno[PIN_LED_ERR]);
+  LED_OFF(fd, pgm->pinno[PIN_LED_ERR]);
   for (werror=0, i=0; i<len; i++) {
     rc = avr_write_byte(fd, p, memtype, addr+i, buf[i]);
     if (rc) {
@@ -371,7 +373,7 @@ int cmd_write(int fd, struct avrpart * p, int argc, char * argv[])
       werror = 1;
     }
     if (werror) {
-      LED_ON(fd, pinno[PIN_LED_ERR]);
+      LED_ON(fd, pgm->pinno[PIN_LED_ERR]);
     }
   }