From 8d3e69c32a40023ce9f65fdfbd32b0d39471d6d1 Mon Sep 17 00:00:00 2001
From: rliebscher <rliebscher@81a1dc3b-b13d-400b-aceb-764788c761c2>
Date: Tue, 17 Jun 2014 20:08:28 +0000
Subject: [PATCH] Removing exit calls from config parser * config.h: cleanup,
 left only internally needed definitions * config.c: removed exit calls, use
 yyerror and yywarning * config_gram.y: (Dito.) * lexer.l: (Dito.) *
 libavrdude.h: removed internal definitions of config parser * main.c: removed
 yyerror, it is now in config.c * jtagmkII.c: added missing free in error case
 * pgm.c: replaced exits by returns * pickit2.c: add missing return

git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@1322 81a1dc3b-b13d-400b-aceb-764788c761c2
---
 ChangeLog     |  13 +++
 config.c      |  65 +++++++++++--
 config.h      | 103 ++++++++++++++++++++
 config_gram.y | 259 ++++++++++++++++++++++++++++----------------------
 jtagmkII.c    |   1 +
 lexer.l       |  22 ++---
 libavrdude.h  |  62 ------------
 main.c        |   5 -
 pgm.c         |   4 +-
 pickit2.c     |   2 +
 10 files changed, 329 insertions(+), 207 deletions(-)
 create mode 100644 config.h

diff --git a/ChangeLog b/ChangeLog
index 08321af5..978d682f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2014-06-17  Rene Liebscher <R.Liebscher@gmx.de>
+
+	Removing exit calls from config parser
+	* config.h: cleanup, left only internally needed definitions
+	* config.c: removed exit calls, use yyerror and yywarning
+	* config_gram.y: (Dito.)
+	* lexer.l: (Dito.)
+	* libavrdude.h: removed internal definitions of config parser
+	* main.c: removed yyerror, it is now in config.c
+	* jtagmkII.c: added missing free in error case
+	* pgm.c: replaced exits by returns
+	* pickit2.c: add missing return
+
 2014-06-13  Axel Wachtler <axel@uracoli.de>
 	
         start removing global "verbose" variable, for avrdude library.
diff --git a/config.c b/config.c
index 11d9e50d..08193cfc 100644
--- a/config.c
+++ b/config.c
@@ -28,6 +28,7 @@
 
 #include "avrdude.h"
 #include "libavrdude.h"
+#include "config.h"
 
 #include "config_gram.h"
 
@@ -87,14 +88,48 @@ int yywrap()
 }
 
 
+int yyerror(char * errmsg, ...)
+{
+  va_list args;
+
+  char message[512];
+
+  va_start(args, errmsg);
+
+  vsnprintf(message, sizeof(message), errmsg, args);
+  avrdude_message(MSG_INFO, "%s: error at %s:%d: %s\n", progname, infile, lineno, message);
+
+  va_end(args);
+
+  return 0;
+}
+
+
+int yywarning(char * errmsg, ...)
+{
+  va_list args;
+
+  char message[512];
+
+  va_start(args, errmsg);
+
+  vsnprintf(message, sizeof(message), errmsg, args);
+  avrdude_message(MSG_INFO, "%s: warning at %s:%d: %s\n", progname, infile, lineno, message);
+
+  va_end(args);
+
+  return 0;
+}
+
+
 TOKEN * new_token(int primary)
 {
   TOKEN * tkn;
 
   tkn = (TOKEN *)malloc(sizeof(TOKEN));
   if (tkn == NULL) {
-    avrdude_message(MSG_INFO, "new_token(): out of memory\n");
-    exit(1);
+    yyerror("new_token(): out of memory");
+    return NULL;
   }
 
   memset(tkn, 0, sizeof(TOKEN));
@@ -141,6 +176,9 @@ TOKEN * number(char * text)
   struct token_t * tkn;
 
   tkn = new_token(TKN_NUMBER);
+  if (tkn == NULL) {
+      return NULL; /* yyerror already called */
+  }
   tkn->value.type   = V_NUM;
   tkn->value.number = atoi(text);
 
@@ -172,11 +210,14 @@ TOKEN * hexnumber(char * text)
   char * e;
 
   tkn = new_token(TKN_NUMBER);
+  if (tkn == NULL) {
+      return NULL; /* yyerror already called */
+  }
   tkn->value.type   = V_NUM;
   tkn->value.number = strtoul(text, &e, 16);
   if ((e == text) || (*e != 0)) {
-    avrdude_message(MSG_INFO, "error at %s:%d: can't scan hex number \"%s\"\n",
-            infile, lineno, text);
+    yyerror("can't scan hex number \"%s\"", text);
+    return NULL;
   }
   
 #if DEBUG
@@ -193,14 +234,17 @@ TOKEN * string(char * text)
   int len;
 
   tkn = new_token(TKN_STRING);
+  if (tkn == NULL) {
+      return NULL; /* yyerror already called */
+  }
 
   len = strlen(text);
 
   tkn->value.type   = V_STR;
   tkn->value.string = (char *) malloc(len+1);
   if (tkn->value.string == NULL) {
-    avrdude_message(MSG_INFO, "id(): out of memory\n");
-    exit(1);
+    yyerror("string(): out of memory");
+    return NULL;
   }
   strcpy(tkn->value.string, text);
 
@@ -264,8 +308,8 @@ char * dup_string(const char * str)
 
   s = strdup(str);
   if (s == NULL) {
-    avrdude_message(MSG_INFO, "dup_string(): out of memory\n");
-    exit(1);
+    yyerror("dup_string(): out of memory");
+    return NULL;
   }
 
   return s;
@@ -279,6 +323,7 @@ extern int yylex_destroy(void);
 int read_config(const char * file)
 {
   FILE * f;
+  int r;
 
   f = fopen(file, "r");
   if (f == NULL) {
@@ -291,7 +336,7 @@ int read_config(const char * file)
   infile = file;
   yyin   = f;
 
-  yyparse();
+  r = yyparse();
 
 #ifdef HAVE_YYLEX_DESTROY
   /* reset lexer and free any allocated memory */
@@ -300,5 +345,5 @@ int read_config(const char * file)
 
   fclose(f);
 
-  return 0;
+  return r;
 }
diff --git a/config.h b/config.h
new file mode 100644
index 00000000..d0d65ae2
--- /dev/null
+++ b/config.h
@@ -0,0 +1,103 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2000-2004  Brian S. Dean <bsd@bsdhome.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* $Id$ */
+
+/* These are the internal definitions needed for config parsing */
+
+#ifndef config_h
+#define config_h
+
+#include "libavrdude.h"
+
+
+#define MAX_STR_CONST 1024
+
+enum { V_NONE, V_NUM, V_NUM_REAL, V_STR };
+typedef struct value_t {
+  int      type;
+  /*union { TODO: use an anonymous union here ? */
+    int      number;
+    double   number_real;
+    char   * string;
+  /*};*/
+} VALUE;
+
+
+typedef struct token_t {
+  int primary;
+  VALUE value;
+} TOKEN;
+typedef struct token_t *token_p;
+
+
+extern FILE       * yyin;
+extern PROGRAMMER * current_prog;
+extern AVRPART    * current_part;
+extern AVRMEM     * current_mem;
+extern int          lineno;
+extern const char * infile;
+extern LISTID       string_list;
+extern LISTID       number_list;
+
+
+#if !defined(HAS_YYSTYPE)
+#define YYSTYPE token_p
+#endif
+extern YYSTYPE yylval;
+
+extern char string_buf[MAX_STR_CONST];
+extern char *string_buf_ptr;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int yyparse(void);
+
+int yyerror(char * errmsg, ...);
+
+int yywarning(char * errmsg, ...);
+
+TOKEN * new_token(int primary);
+
+void free_token(TOKEN * tkn);
+
+void free_tokens(int n, ...);
+
+TOKEN * number(char * text);
+
+TOKEN * number_real(char * text);
+
+TOKEN * hexnumber(char * text);
+
+TOKEN * string(char * text);
+
+TOKEN * keyword(int primary);
+
+void print_token(TOKEN * tkn);
+
+void pyytext(void);
+
+char * dup_string(const char * str);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/config_gram.y b/config_gram.y
index 09dc6e65..3b41ca11 100644
--- a/config_gram.y
+++ b/config_gram.y
@@ -28,18 +28,19 @@
 
 #include "avrdude.h"
 #include "libavrdude.h"
-
-#include "par.h"
-#include "serbb.h"
-#include "ppi.h"
+#include "config.h"
 
 #if defined(WIN32NATIVE)
 #define strtok_r( _s, _sep, _lasts ) \
     ( *(_lasts) = strtok( (_s), (_sep) ) )
 #endif
 
+#define STRINGIFY(x) #x
+#define TOSTRING(x) STRINGIFY(x)
+
 int yylex(void);
-int yyerror(char * errmsg);
+int yyerror(char * errmsg, ...);
+int yywarning(char * errmsg, ...);
 
 static int assign_pin(int pinno, TOKEN * v, int invert);
 static int assign_pin_list(int invert);
@@ -271,22 +272,22 @@ prog_def :
       PROGRAMMER * existing_prog;
       char * id;
       if (lsize(current_prog->id) == 0) {
-        avrdude_message(MSG_INFO, "%s: error at %s:%d: required parameter id not specified\n",
-                progname, infile, lineno);
-        exit(1);
+        yyerror("required parameter id not specified");
+        YYABORT;
       }
       if (current_prog->initpgm == NULL) {
-        avrdude_message(MSG_INFO, "%s: error at %s:%d: programmer type not specified\n",
-                progname, infile, lineno);
-        exit(1);
+        yyerror("programmer type not specified");
+        YYABORT;
       }
       id = ldata(lfirst(current_prog->id));
       existing_prog = locate_programmer(programmers, id);
       if (existing_prog) {
-        avrdude_message(MSG_INFO, "%s: warning at %s:%d: programmer %s overwrites "
-                "previous definition %s:%d.\n",
-                progname, infile, current_prog->lineno,
+        { /* temporarly set lineno to lineno of programmer start */
+          int temp = lineno; lineno = current_prog->lineno;
+          yywarning("programmer %s overwrites previous definition %s:%d.",
                 id, existing_prog->config_file, existing_prog->lineno);
+          lineno = temp;
+        }
         lrmv_d(programmers, existing_prog);
         pgm_free(existing_prog);
       }
@@ -301,6 +302,10 @@ prog_def :
 prog_decl :
   K_PROGRAMMER
     { current_prog = pgm_new();
+      if (current_prog == NULL) {
+        yyerror("could not create pgm instance");
+        YYABORT;
+      }
       strcpy(current_prog->config_file, infile);
       current_prog->lineno = lineno;
     }
@@ -309,11 +314,16 @@ prog_decl :
     {
       struct programmer_t * pgm = locate_programmer(programmers, $3->value.string);
       if (pgm == NULL) {
-        avrdude_message(MSG_INFO, "%s: error at %s:%d: parent programmer %s not found\n",
-                progname, infile, lineno, $3->value.string);
-        exit(1);
+        yyerror("parent programmer %s not found", $3->value.string);
+        free_token($3);
+        YYABORT;
       }
       current_prog = pgm_dup(pgm);
+      if (current_prog == NULL) {
+        yyerror("could not duplicate pgm instance");
+        free_token($3);
+        YYABORT;
+      }
       strcpy(current_prog->config_file, infile);
       current_prog->lineno = lineno;
       free_token($3);
@@ -329,9 +339,8 @@ part_def :
       AVRPART * existing_part;
 
       if (current_part->id[0] == 0) {
-        avrdude_message(MSG_INFO, "%s: error at %s:%d: required parameter id not specified\n",
-                progname, infile, lineno);
-        exit(1);
+        yyerror("required parameter id not specified");
+        YYABORT;
       }
 
       /*
@@ -343,26 +352,21 @@ part_def :
         m = ldata(ln);
         if (m->paged) {
           if (m->page_size == 0) {
-            avrdude_message(MSG_INFO, "%s: error at %s:%d: must specify page_size for paged "
-                    "memory\n",
-                    progname, infile, lineno);
-            exit(1);
+            yyerror("must specify page_size for paged memory");
+            YYABORT;
           }
           if (m->num_pages == 0) {
-            avrdude_message(MSG_INFO, "%s: error at %s:%d: must specify num_pages for paged "
-                    "memory\n",
-                    progname, infile, lineno);
-            exit(1);
+            yyerror("must specify num_pages for paged memory");
+            YYABORT;
           }
           if (m->size != m->page_size * m->num_pages) {
-            avrdude_message(MSG_INFO, "%s: error at %s:%d: page size (%u) * num_pages (%u) = "
-                    "%u does not match memory size (%u)\n",
-                    progname, infile, lineno,
-                    m->page_size, 
-                    m->num_pages, 
+            yyerror("page size (%u) * num_pages (%u) = "
+                    "%u does not match memory size (%u)",
+                    m->page_size,
+                    m->num_pages,
                     m->page_size * m->num_pages,
                     m->size);
-            exit(1);
+            YYABORT;
           }
 
         }
@@ -370,10 +374,13 @@ part_def :
 
       existing_part = locate_part(part_list, current_part->id);
       if (existing_part) {
-        avrdude_message(MSG_INFO, "%s: warning at %s:%d: part %s overwrites "
-                "previous definition %s:%d.\n",
-                progname, infile, current_part->lineno, current_part->id,
+        { /* temporarly set lineno to lineno of part start */
+          int temp = lineno; lineno = current_part->lineno;
+          yywarning("part %s overwrites previous definition %s:%d.",
+                current_part->id,
                 existing_part->config_file, existing_part->lineno);
+          lineno = temp;
+        }
         lrmv_d(part_list, existing_part);
         avr_free_part(existing_part);
       }
@@ -386,6 +393,10 @@ part_decl :
   K_PART
     {
       current_part = avr_new_part();
+      if (current_part == NULL) {
+        yyerror("could not create part instance");
+        YYABORT;
+      }
       strcpy(current_part->config_file, infile);
       current_part->lineno = lineno;
     } |
@@ -393,12 +404,17 @@ part_decl :
     {
       AVRPART * parent_part = locate_part(part_list, $3->value.string);
       if (parent_part == NULL) {
-        avrdude_message(MSG_INFO, "%s: error at %s:%d: can't find parent part",
-              progname, infile, lineno);
-        exit(1);
+        yyerror("can't find parent part");
+        free_token($3);
+        YYABORT;
       }
 
       current_part = avr_dup_part(parent_part);
+      if (current_part == NULL) {
+        yyerror("could not duplicate part instance");
+        free_token($3);
+        YYABORT;
+      }
       strcpy(current_part->config_file, infile);
       current_part->lineno = lineno;
 
@@ -426,11 +442,24 @@ prog_parm :
   K_ID TKN_EQUAL string_list {
     {
       TOKEN * t;
+      char *s;
+      int do_yyabort = 0;
       while (lsize(string_list)) {
         t = lrmv_n(string_list, 1);
-        ladd(current_prog->id, dup_string(t->value.string));
+        if (!do_yyabort) {
+          s = dup_string(t->value.string);
+          if (s == NULL) {
+            do_yyabort = 1;
+          } else {
+            ladd(current_prog->id, s);
+          }
+        }
+        /* if do_yyabort == 1 just make the list empty */
         free_token(t);
       }
+      if (do_yyabort) {
+        YYABORT;
+      }
     }
   } |
   prog_parm_type
@@ -462,18 +491,17 @@ prog_parm_type_id:
   TKN_STRING        {
   const struct programmer_type_t * pgm_type = locate_programmer_type($1->value.string);
     if (pgm_type == NULL) {
-        avrdude_message(MSG_INFO, "%s: error at %s:%d: programmer type %s not found\n",
-                progname, infile, lineno, $1->value.string);
-        exit(1);
+        yyerror("programmer type %s not found", $1->value.string);
+        free_token($1); 
+        YYABORT;
     }
     current_prog->initpgm = pgm_type->initpgm;
     free_token($1); 
 }
   | error
 {
-        avrdude_message(MSG_INFO, "%s: error at %s:%d: programmer type must be written as \"id_type\"\n",
-                progname, infile, lineno);
-        exit(1);
+        yyerror("programmer type must be written as \"id_type\"");
+        YYABORT;
 }
 ;
 
@@ -549,9 +577,9 @@ usb_pid_list:
 ;
 
 pin_number_non_empty:
-  TKN_NUMBER { assign_pin(pin_name, $1, 0);  }
+  TKN_NUMBER { if(0 != assign_pin(pin_name, $1, 0)) YYABORT;  }
   |
-  TKN_TILDE TKN_NUMBER { assign_pin(pin_name, $2, 1); }
+  TKN_TILDE TKN_NUMBER { if(0 != assign_pin(pin_name, $2, 1)) YYABORT; }
 ;
 
 pin_number:
@@ -563,7 +591,7 @@ pin_number:
 pin_list_element:
   pin_number_non_empty
   |
-  TKN_TILDE TKN_LEFT_PAREN num_list TKN_RIGHT_PAREN { assign_pin_list(1); }
+  TKN_TILDE TKN_LEFT_PAREN num_list TKN_RIGHT_PAREN { if(0 != assign_pin_list(1)) YYABORT; }
 ;
 
 pin_list_non_empty:
@@ -643,10 +671,9 @@ part_parm :
 
   K_DEVICECODE TKN_EQUAL TKN_NUMBER {
     {
-      avrdude_message(MSG_INFO, "%s: error at %s:%d: devicecode is deprecated, use "
-              "stk500_devcode instead\n",
-              progname, infile, lineno);
-      exit(1);
+      yyerror("devicecode is deprecated, use "
+              "stk500_devcode instead");
+      YYABORT;
     }
   } |
 
@@ -708,9 +735,7 @@ part_parm :
       }
       if (!ok)
 	{
-	  avrdude_message(MSG_INFO, "%s: Warning: line %d of %s: "
-		  "too many bytes in control stack\n",
-                  progname, lineno, infile);
+	  yywarning("too many bytes in control stack");
         }
     }
   } |
@@ -741,9 +766,7 @@ part_parm :
       }
       if (!ok)
 	{
-	  avrdude_message(MSG_INFO, "%s: Warning: line %d of %s: "
-		  "too many bytes in control stack\n",
-                  progname, lineno, infile);
+	  yywarning("too many bytes in control stack");
         }
     }
   } |
@@ -773,9 +796,7 @@ part_parm :
       }
       if (!ok)
 	{
-	  avrdude_message(MSG_INFO, "%s: Warning: line %d of %s: "
-		  "too many bytes in flash instructions\n",
-                  progname, lineno, infile);
+	  yywarning("too many bytes in flash instructions");
         }
     }
   } |
@@ -805,9 +826,7 @@ part_parm :
       }
       if (!ok)
 	{
-	  avrdude_message(MSG_INFO, "%s: Warning: line %d of %s: "
-		  "too many bytes in EEPROM instructions\n",
-                  progname, lineno, infile);
+	  yywarning("too many bytes in EEPROM instructions");
         }
     }
   } |
@@ -1179,16 +1198,21 @@ part_parm :
     mem_specs |
 
   K_FLASH { current_mem = AVR_M_FLASH; }
-    mem_specs | 
+    mem_specs |
 */
 
   K_MEMORY TKN_STRING 
-    { 
-      current_mem = avr_new_memtype(); 
-      strncpy(current_mem->desc, $2->value.string, AVR_MEMDESCLEN); 
+    {
+      current_mem = avr_new_memtype();
+      if (current_mem == NULL) {
+        yyerror("could not create mem instance");
+        free_token($2);
+        YYABORT;
+      }
+      strncpy(current_mem->desc, $2->value.string, AVR_MEMDESCLEN);
       current_mem->desc[AVR_MEMDESCLEN-1] = 0;
-      free_token($2); 
-    } 
+      free_token($2);
+    }
     mem_specs 
     { 
       AVRMEM * existing_mem;
@@ -1208,11 +1232,16 @@ part_parm :
       OPCODE * op;
 
       opnum = which_opcode($1);
+      if (opnum < 0) YYABORT;
       op = avr_new_opcode();
-      parse_cmdbits(op);
+      if (op == NULL) {
+        yyerror("could not create opcode instance");
+        free_token($1);
+        YYABORT;
+      }
+      if(0 != parse_cmdbits(op)) YYABORT;
       if (current_part->op[opnum] != NULL) {
-        /*avrdude_message(MSG_INFO, "%s: warning at %s:%d: operation redefined\n",
-              progname, infile, lineno);*/
+        /*yywarning("operation redefined");*/
         avr_free_opcode(current_part->op[opnum]);
       }
       current_part->op[opnum] = op;
@@ -1334,11 +1363,16 @@ mem_spec :
       OPCODE * op;
 
       opnum = which_opcode($1);
+      if (opnum < 0) YYABORT;
       op = avr_new_opcode();
-      parse_cmdbits(op);
+      if (op == NULL) {
+        yyerror("could not create opcode instance");
+        free_token($1);
+        YYABORT;
+      }
+      if(0 != parse_cmdbits(op)) YYABORT;
       if (current_mem->op[opnum] != NULL) {
-        /*avrdude_message(MSG_INFO, "%s: warning at %s:%d: operation redefined\n",
-              progname, infile, lineno);*/
+        /*yywarning("operation redefined");*/
         avr_free_opcode(current_mem->op[opnum]);
       }
       current_mem->op[opnum] = op;
@@ -1373,10 +1407,8 @@ static int assign_pin(int pinno, TOKEN * v, int invert)
   free_token(v);
 
   if ((value < PIN_MIN) || (value > PIN_MAX)) {
-    avrdude_message(MSG_INFO, "%s: error at line %d of %s: pin must be in the "
-            "range %d-%d\n",
-            progname, lineno, infile, PIN_MIN, PIN_MAX);
-    exit(1);
+    yyerror("pin must be in the range " TOSTRING(PIN_MIN) "-"  TOSTRING(PIN_MAX));
+    return -1;
   }
 
   pin_set_value(&(current_prog->pin[pinno]), value, invert);
@@ -1388,23 +1420,23 @@ static int assign_pin_list(int invert)
 {
   TOKEN * t;
   int pin;
+  int rv = 0;
 
   current_prog->pinno[pin_name] = 0;
   while (lsize(number_list)) {
     t = lrmv_n(number_list, 1);
-    pin = t->value.number;
-    if ((pin < PIN_MIN) || (pin > PIN_MAX)) {
-      avrdude_message(MSG_INFO, "%s: error at line %d of %s: pin must be in the "
-            "range %d-%d\n",
-            progname, lineno, infile, PIN_MIN, PIN_MAX);
-      exit(1);
-      /* TODO clear list and free tokens if no exit is done */
+    if (rv == 0) {
+      pin = t->value.number;
+      if ((pin < PIN_MIN) || (pin > PIN_MAX)) {
+        yyerror("pin must be in the range " TOSTRING(PIN_MIN) "-"  TOSTRING(PIN_MAX));
+        rv = -1;
+      /* loop clears list and frees tokens */
+      }
+      pin_set_value(&(current_prog->pin[pin_name]), pin, invert);
     }
-    pin_set_value(&(current_prog->pin[pin_name]), pin, invert);
     free_token(t);
   }
-
-  return 0;
+  return rv;
 }
 
 static int which_opcode(TOKEN * opcode)
@@ -1423,9 +1455,8 @@ static int which_opcode(TOKEN * opcode)
     case K_CHIP_ERASE  : return AVR_OP_CHIP_ERASE; break;
     case K_PGM_ENABLE  : return AVR_OP_PGM_ENABLE; break;
     default :
-      avrdude_message(MSG_INFO, "%s: error at %s:%d: invalid opcode\n",
-              progname, infile, lineno);
-      exit(1);
+      yyerror("invalid opcode");
+      return -1;
       break;
   }
 }
@@ -1440,6 +1471,7 @@ static int parse_cmdbits(OPCODE * op)
   char * q;
   int len;
   char * s, *brkt = NULL;
+  int rv = 0;
 
   bitno = 32;
   while (lsize(string_list)) {
@@ -1447,21 +1479,21 @@ static int parse_cmdbits(OPCODE * op)
     t = lrmv_n(string_list, 1);
 
     s = strtok_r(t->value.string, " ", &brkt);
-    while (s != NULL) {
+    while (rv == 0 && s != NULL) {
 
       bitno--;
       if (bitno < 0) {
-        avrdude_message(MSG_INFO, "%s: error at %s:%d: too many opcode bits for instruction\n",
-                progname, infile, lineno);
-        exit(1);
+        yyerror("too many opcode bits for instruction");
+        rv = -1;
+        break;
       }
 
       len = strlen(s);
 
       if (len == 0) {
-        avrdude_message(MSG_INFO, "%s: error at %s:%d: invalid bit specifier \"\"\n",
-                progname, infile, lineno);
-        exit(1);
+        yyerror("invalid bit specifier \"\"");
+        rv = -1;
+        break;
       }
 
       ch = s[0];
@@ -1499,9 +1531,8 @@ static int parse_cmdbits(OPCODE * op)
             op->bit[bitno].bitno = bitno % 8;
             break;
           default :
-            avrdude_message(MSG_INFO, "%s: error at %s:%d: invalid bit specifier '%c'\n",
-                    progname, infile, lineno, ch);
-            exit(1);
+            yyerror("invalid bit specifier '%c'", ch);
+            rv = -1;
             break;
         }
       }
@@ -1510,28 +1541,26 @@ static int parse_cmdbits(OPCODE * op)
           q = &s[1];
           op->bit[bitno].bitno = strtol(q, &e, 0);
           if ((e == q)||(*e != 0)) {
-            avrdude_message(MSG_INFO, "%s: error at %s:%d: can't parse bit number from \"%s\"\n",
-                    progname, infile, lineno, q);
-            exit(1);
+            yyerror("can't parse bit number from \"%s\"", q);
+            rv = -1;
+            break;
           }
           op->bit[bitno].type = AVR_CMDBIT_ADDRESS;
           op->bit[bitno].value = 0;
         }
         else {
-          avrdude_message(MSG_INFO, "%s: error at %s:%d: invalid bit specifier \"%s\"\n",
-                  progname, infile, lineno, s);
-          exit(1);
+          yyerror("invalid bit specifier \"%s\"", s);
+          rv = -1;
+          break;
         }
       }
 
       s = strtok_r(NULL, " ", &brkt);
-    }
+    } /* while */
 
     free_token(t);
 
   }  /* while */
 
-  return 0;
+  return rv;
 }
-
-
diff --git a/jtagmkII.c b/jtagmkII.c
index 0b65539e..6e49b84d 100644
--- a/jtagmkII.c
+++ b/jtagmkII.c
@@ -445,6 +445,7 @@ int jtagmkII_send(PROGRAMMER * pgm, unsigned char * data, size_t len)
   if (serial_send(&pgm->fd, buf, len + 10) != 0) {
     avrdude_message(MSG_INFO, "%s: jtagmkII_send(): failed to send command to serial port\n",
                     progname);
+    free(buf);
     return -1;
   }
 
diff --git a/lexer.l b/lexer.l
index 338fd63c..34af33d6 100644
--- a/lexer.l
+++ b/lexer.l
@@ -30,6 +30,7 @@
 
 #include "avrdude.h"
 #include "libavrdude.h"
+#include "config.h"
 
 #include "config_gram.h"
 
@@ -94,12 +95,8 @@ SIGN     [+-]
           }
           
           if (c == EOF) {
-            avrdude_message(MSG_INFO, "error at %s:%d: EOF in comment\n", 
-                    infile, lineno);
-            avrdude_message(MSG_INFO, "    comment started on line %d\n", 
-                    comment_start);
-            exit(1);
-            break;
+            yyerror("EOF in comment (started on line %d)", comment_start);
+            return YYERRCODE;
           }
         }
      }
@@ -115,9 +112,9 @@ SIGN     [+-]
 <strng>\\(.|\n)  *(string_buf_ptr++) = yytext[1];
 <strng>[^\\\n\"]+ { char *yptr = yytext; while (*yptr) 
                                          *(string_buf_ptr++) = *(yptr++); }
-<strng>\n { avrdude_message(MSG_INFO, "error at line %d: unterminated character constant\n",
-            lineno); 
-            exit(1); }
+
+<strng>\n { yyerror("unterminated character constant");
+            return YYERRCODE; }
 
 allowfullpagebitstream { yylval=NULL; return K_ALLOWFULLPAGEBITSTREAM; }
 avr910_devcode   { yylval=NULL; return K_AVR910_DEVCODE; }
@@ -254,10 +251,9 @@ yes              { yylval=new_token(K_YES); return K_YES; }
 "\n"      { lineno++; }
 [ \r\t]+  { /* ignore whitespace */ }
 
-c: { avrdude_message(MSG_INFO, "error at %s:%d: possible old-style config file entry\n",
-             infile, lineno);
-     avrdude_message(MSG_INFO, "  Update your config file (see %s%s for a sample)\n",
-             CONFIG_DIR, "/avrdude.conf.sample");
+c: { yyerror("possible old-style config file entry\n"
+             "  Update your config file (see " CONFIG_DIR 
+               "/avrdude.conf.sample for a sample)");
      return YYERRCODE; }
 
 . { return YYERRCODE; }
diff --git a/libavrdude.h b/libavrdude.h
index 9689762d..7edcad50 100644
--- a/libavrdude.h
+++ b/libavrdude.h
@@ -893,34 +893,6 @@ void walk_programmer_types(/*LISTID programmer_types,*/ walk_programmer_types_cb
 
 /* formerly config.h */
 
-#define MAX_STR_CONST 1024
-
-enum { V_NONE, V_NUM, V_NUM_REAL, V_STR };
-typedef struct value_t {
-  int      type;
-  /*union { TODO: use an anonymous union here ? */
-    int      number;
-    double   number_real;
-    char   * string;
-  /*};*/
-} VALUE;
-
-
-typedef struct token_t {
-  int primary;
-  VALUE value;
-} TOKEN;
-typedef struct token_t *token_p;
-
-
-extern FILE       * yyin;
-extern PROGRAMMER * current_prog;
-extern AVRPART    * current_part;
-extern AVRMEM     * current_mem;
-extern int          lineno;
-extern const char * infile;
-extern LISTID       string_list;
-extern LISTID       number_list;
 extern LISTID       part_list;
 extern LISTID       programmers;
 extern char         default_programmer[];
@@ -933,48 +905,14 @@ extern int          default_safemode;
  * default_parallel and default_serial. */
 #define DEFAULT_USB "usb"
 
-
-#if !defined(HAS_YYSTYPE)
-#define YYSTYPE token_p
-#endif
-extern YYSTYPE yylval;
-
-extern char string_buf[MAX_STR_CONST];
-extern char *string_buf_ptr;
-
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-int yyparse(void);
-
-
 int init_config(void);
 
 void cleanup_config(void);
 
-TOKEN * new_token(int primary);
-
-void free_token(TOKEN * tkn);
-
-void free_tokens(int n, ...);
-
-TOKEN * number(char * text);
-
-TOKEN * number_real(char * text);
-
-TOKEN * hexnumber(char * text);
-
-TOKEN * string(char * text);
-
-TOKEN * keyword(int primary);
-
-void print_token(TOKEN * tkn);
-
-void pyytext(void);
-
-char * dup_string(const char * str);
-
 int read_config(const char * file);
 
 #ifdef __cplusplus
diff --git a/main.c b/main.c
index 812d6470..44d1869b 100644
--- a/main.c
+++ b/main.c
@@ -71,11 +71,6 @@ int avrdude_message(const int msglvl, const char *format, ...)
     return rc;
 }
 
-int yyerror(char * errmsg)
-{
-  avrdude_message(MSG_INFO, "%s: %s at %s:%d\n", progname, errmsg, infile, lineno);
-  exit(1);
-}
 
 struct list_walk_cookie
 {
diff --git a/pgm.c b/pgm.c
index b2ffaf93..851ac5a8 100644
--- a/pgm.c
+++ b/pgm.c
@@ -70,7 +70,7 @@ PROGRAMMER * pgm_new(void)
   if (pgm == NULL) {
     avrdude_message(MSG_INFO, "%s: out of memory allocating programmer structure\n",
             progname);
-    exit(1);
+    return NULL;
   }
 
   memset(pgm, 0, sizeof(*pgm));
@@ -161,7 +161,7 @@ PROGRAMMER * pgm_dup(const PROGRAMMER * const src)
   if (pgm == NULL) {
     avrdude_message(MSG_INFO, "%s: out of memory allocating programmer structure\n",
             progname);
-    exit(1);
+    return NULL;
   }
 
   memcpy(pgm, src, sizeof(*pgm));
diff --git a/pickit2.c b/pickit2.c
index 7ea9f000..b5c8a04c 100644
--- a/pickit2.c
+++ b/pickit2.c
@@ -1318,6 +1318,8 @@ static int pickit2_nousb_open (struct programmer_t *pgm, char * name) {
             "%s: error: no usb support. Please compile again with libusb installed.\n",
 #endif
             progname);
+
+    return -1;
 }
 
 void pickit2_initpgm (PROGRAMMER * pgm)