From 8a5c0972ab2d1e703487db4b06409ea0009fec4e Mon Sep 17 00:00:00 2001
From: rliebscher <rliebscher@81a1dc3b-b13d-400b-aceb-764788c761c2>
Date: Thu, 29 Dec 2011 16:51:44 +0000
Subject: [PATCH] bug #34302: Feature request : device configuration with
 parent classes (not in original patch) * avrpart.c: New function
 avr_dup_opcode. avr_dup_mem/avr_dup_part- 	functions now duplicate the
 opcodes in their op-array to avoid memory leaks. * doc/avrdude.texi: Added
 description of part parent f

git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@1028 81a1dc3b-b13d-400b-aceb-764788c761c2
---
 ChangeLog        | 15 ++++++++++++
 avrdude.conf.in  | 25 ++++++++++++++++---
 avrpart.c        | 62 ++++++++++++++++++++++++++++++++++++-----------
 config_gram.y    | 63 ++++++++++++++++++++++++++----------------------
 doc/avrdude.texi | 23 +++++++++++++++++-
 lexer.l          |  1 +
 6 files changed, 141 insertions(+), 48 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 6d6c4f6d..462665a2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,18 @@
+2011-12-29  Rene Liebscher <R.Liebscher@gmx.de>
+
+	bug #34302: Feature request : device configuration with parent classes
+	* config_gram.y: Added part parent rule and allow overwriting existing
+	data at several places
+	* avrdude.conf.in: Added description comment and m328/m328p as example
+	* avrpart.c: avr_dup_mem-functions now copy buf and tags memory block 
+	only they are already allocated.
+	* lexer.l: Added parent as valid token
+	
+	(not in original patch) 
+	* avrpart.c: New function avr_dup_opcode. avr_dup_mem/avr_dup_part-
+	functions now duplicate the opcodes in their op-array to avoid memory leaks.
+	* doc/avrdude.texi: Added description of part parent feature
+
 2011-12-29  Rene Liebscher <R.Liebscher@gmx.de>
 
 	patch #7687: Autogenerating programmers and parts lists for docs
diff --git a/avrdude.conf.in b/avrdude.conf.in
index 06b82a78..fe727e5c 100644
--- a/avrdude.conf.in
+++ b/avrdude.conf.in
@@ -138,6 +138,17 @@
 # values.  If a required parameter is left empty, AVRDUDE will
 # complain.
 #
+# Parts can also inherit parameters from previously defined parts
+# using the following syntax. In this case specified integer and 
+# string values override parameter values from the parent part. New 
+# memory definitions are added to the definitions inherited from the 
+# parent.
+#
+#   part parent <id>                              # quoted string
+#       id               = <id> ;                 # quoted string
+#       <any set of other parameters from the list above>
+#     ;
+#
 # NOTES:
 #   * 'devicecode' is the device code used by the STK500 (see codes 
 #       listed below)
@@ -9223,12 +9234,12 @@ part
   ;
 
 #------------------------------------------------------------
-# ATmega328P
+# ATmega328
 #------------------------------------------------------------
 
 part
-    id			= "m328p";
-    desc		= "ATmega328P";
+    id			= "m328";
+    desc		= "ATmega328";
     has_debugwire	= yes;
     flash_instr		= 0xB6, 0x01, 0x11;
     eeprom_instr	= 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00,
@@ -9236,7 +9247,7 @@ part
 			  0x99, 0xF9, 0xBB, 0xAF;
     stk500_devcode	= 0x86;
     # avr910_devcode	= 0x;
-    signature		= 0x1e 0x95 0x0F;
+    signature		= 0x1e 0x95 0x14;
     pagel		= 0xd7;
     bs2			= 0xc2;
     chip_erase_delay	= 9000;
@@ -9410,6 +9421,12 @@ part
     ;
 ;
 
+part parent "m328"
+    id			= "m328p";
+    desc		= "ATmega328P";
+    signature		= 0x1e 0x95 0x0F;
+;
+
 #------------------------------------------------------------
 # ATtiny2313
 #------------------------------------------------------------
diff --git a/avrpart.c b/avrpart.c
index 90097a91..0dba3f64 100644
--- a/avrpart.c
+++ b/avrpart.c
@@ -47,6 +47,26 @@ OPCODE * avr_new_opcode(void)
   return m;
 }
 
+static OPCODE * avr_dup_opcode(OPCODE * op)
+{
+  OPCODE * m;
+  
+  /* this makes life easier */
+  if (op == NULL) {
+    return NULL;
+  }
+
+  m = (OPCODE *)malloc(sizeof(*m));
+  if (m == NULL) {
+    fprintf(stderr, "avr_dup_opcode(): out of memory\n");
+    exit(1);
+  }
+
+  memcpy(m, op, sizeof(*m));
+
+  return m;
+}
+
 
 /*
  * avr_set_bits()
@@ -248,28 +268,37 @@ int avr_initmem(AVRPART * p)
 AVRMEM * avr_dup_mem(AVRMEM * m)
 {
   AVRMEM * n;
+  int i;
 
   n = avr_new_memtype();
 
   *n = *m;
 
-  n->buf = (unsigned char *)malloc(n->size);
-  if (n->buf == NULL) {
-    fprintf(stderr,
-            "avr_dup_mem(): out of memory (memsize=%d)\n",
-            n->size);
-    exit(1);
+  if (m->buf != NULL) {
+    n->buf = (unsigned char *)malloc(n->size);
+    if (n->buf == NULL) {
+      fprintf(stderr,
+              "avr_dup_mem(): out of memory (memsize=%d)\n",
+              n->size);
+      exit(1);
+    }
+    memcpy(n->buf, m->buf, n->size);
   }
-  memcpy(n->buf, m->buf, n->size);
 
-  n->tags = (unsigned char *)malloc(n->size);
-  if (n->tags == NULL) {
-    fprintf(stderr,
-            "avr_dup_mem(): out of memory (memsize=%d)\n",
-            n->size);
-    exit(1);
+  if (m->tags != NULL) {
+    n->tags = (unsigned char *)malloc(n->size);
+    if (n->tags == NULL) {
+      fprintf(stderr,
+              "avr_dup_mem(): out of memory (memsize=%d)\n",
+              n->size);
+      exit(1);
+    }
+    memcpy(n->tags, m->tags, n->size);
+  }
+
+  for (i = 0; i < AVR_OP_MAX; i++) {
+    n->op[i] = avr_dup_opcode(n->op[i]);
   }
-  memcpy(n->tags, m->tags, n->size);
 
   return n;
 }
@@ -398,6 +427,7 @@ AVRPART * avr_dup_part(AVRPART * d)
   AVRPART * p;
   LISTID save;
   LNODEID ln;
+  int i;
 
   p = avr_new_part();
   save = p->mem;
@@ -410,6 +440,10 @@ AVRPART * avr_dup_part(AVRPART * d)
     ladd(p->mem, avr_dup_mem(ldata(ln)));
   }
 
+  for (i = 0; i < AVR_OP_MAX; i++) {
+    p->op[i] = avr_dup_opcode(p->op[i]);
+  }
+
   return p;
 }
 
diff --git a/config_gram.y b/config_gram.y
index df6619c8..d25fe3bf 100644
--- a/config_gram.y
+++ b/config_gram.y
@@ -128,6 +128,7 @@ static int pin_name;
 %token K_PAGEL
 %token K_PAR
 %token K_PARALLEL
+%token K_PARENT
 %token K_PART
 %token K_PGMLED
 %token K_PROGRAMMER
@@ -316,13 +317,7 @@ prog_decl :
 
 
 part_def :
-  K_PART
-    {
-      current_part = avr_new_part();
-      strcpy(current_part->config_file, infile);
-      current_part->lineno = lineno;
-    }
-    part_parms 
+  part_decl part_parms 
     { 
       LNODEID ln;
       AVRMEM * m;
@@ -376,6 +371,30 @@ part_def :
     }
 ;
 
+part_decl :
+  K_PART
+    {
+      current_part = avr_new_part();
+      strcpy(current_part->config_file, infile);
+      current_part->lineno = lineno;
+    } |
+  K_PART K_PARENT TKN_STRING 
+    {
+      AVRPART * parent_part = locate_part(part_list, $3->value.string);
+      if (parent_part == NULL) {
+        fprintf(stderr, 
+              "%s: error at %s:%d: can't find parent part",
+              progname, infile, lineno);
+        exit(1);
+      }
+
+      current_part = avr_dup_part(parent_part);
+      strcpy(current_part->config_file, infile);
+      current_part->lineno = lineno;
+
+      free_token($3);
+    }
+;
 
 string_list :
   TKN_STRING { ladd(string_list, $1); } |
@@ -632,19 +651,11 @@ part_parm :
       unsigned nbytes;
       int ok;
 
-      if (current_part->ctl_stack_type != CTL_STACK_NONE)
-	{
-	  fprintf(stderr,
-		  "%s: error at line %d of %s: "
-		  "control stack already defined\n",
-		  progname, lineno, infile);
-	  exit(1);
-	}
-
       current_part->ctl_stack_type = CTL_STACK_PP;
       nbytes = 0;
       ok = 1;
 
+      memset(current_part->controlstack, 0, CTL_STACK_SIZE);
       while (lsize(number_list)) {
         t = lrmv_n(number_list, 1);
 	if (nbytes < CTL_STACK_SIZE)
@@ -674,19 +685,11 @@ part_parm :
       unsigned nbytes;
       int ok;
 
-      if (current_part->ctl_stack_type != CTL_STACK_NONE)
-	{
-	  fprintf(stderr,
-		  "%s: error at line %d of %s: "
-		  "control stack already defined\n",
-		  progname, lineno, infile);
-	  exit(1);
-	}
-
       current_part->ctl_stack_type = CTL_STACK_HVSP;
       nbytes = 0;
       ok = 1;
 
+      memset(current_part->controlstack, 0, CTL_STACK_SIZE);
       while (lsize(number_list)) {
         t = lrmv_n(number_list, 1);
 	if (nbytes < CTL_STACK_SIZE)
@@ -719,6 +722,7 @@ part_parm :
       nbytes = 0;
       ok = 1;
 
+      memset(current_part->flash_instr, 0, FLASH_INSTR_SIZE);
       while (lsize(number_list)) {
         t = lrmv_n(number_list, 1);
 	if (nbytes < FLASH_INSTR_SIZE)
@@ -751,6 +755,7 @@ part_parm :
       nbytes = 0;
       ok = 1;
 
+      memset(current_part->eeprom_instr, 0, EEPROM_INSTR_SIZE);
       while (lsize(number_list)) {
         t = lrmv_n(number_list, 1);
 	if (nbytes < EEPROM_INSTR_SIZE)
@@ -1154,9 +1159,9 @@ part_parm :
       op = avr_new_opcode();
       parse_cmdbits(op);
       if (current_part->op[opnum] != NULL) {
-        fprintf(stderr,
+        /*fprintf(stderr,
               "%s: warning at %s:%d: operation redefined\n",
-              progname, infile, lineno);
+              progname, infile, lineno);*/
         free(current_part->op[opnum]);
       }
       current_part->op[opnum] = op;
@@ -1281,9 +1286,9 @@ mem_spec :
       op = avr_new_opcode();
       parse_cmdbits(op);
       if (current_mem->op[opnum] != NULL) {
-        fprintf(stderr,
+        /*fprintf(stderr,
               "%s: warning at %s:%d: operation redefined\n",
-              progname, infile, lineno);
+              progname, infile, lineno);*/
         free(current_mem->op[opnum]);
       }
       current_mem->op[opnum] = op;
diff --git a/doc/avrdude.texi b/doc/avrdude.texi
index d822d372..da9a3bbd 100644
--- a/doc/avrdude.texi
+++ b/doc/avrdude.texi
@@ -1529,13 +1529,34 @@ part
 @end smallexample
 
 @menu
+* Parent Part::
 * Instruction Format::
 @end menu
 
 @c
 @c Node
 @c
-@node Instruction Format,  , Part Definitions, Part Definitions
+@node Parent Part, Instruction Format, Part Definitions, Part Definitions
+@subsection Parent Part
+
+@noindent
+Parts can also inherit parameters from previously defined parts
+using the following syntax. In this case specified integer and 
+string values override parameter values from the parent part. New 
+memory definitions are added to the definitions inherited from the 
+parent.
+
+@smallexample
+   part parent <id>                              # quoted string
+       id               = <id> ;                 # quoted string
+       <any set of other parameters from the list above>
+     ;
+@end smallexample
+
+@c
+@c Node
+@c
+@node Instruction Format,  , Parent Part, Part Definitions
 @subsection Instruction Format
 
 @noindent
diff --git a/lexer.l b/lexer.l
index 9870e7c6..a57ac237 100644
--- a/lexer.l
+++ b/lexer.l
@@ -177,6 +177,7 @@ paged            { yylval=NULL; return K_PAGED; }
 pagel            { yylval=NULL; return K_PAGEL; }
 par              { yylval=NULL; return K_PAR; }
 parallel         { yylval=NULL; return K_PARALLEL; }
+parent           { yylval=NULL; return K_PARENT; }
 part             { yylval=NULL; return K_PART; }
 pgmled           { yylval=NULL; return K_PGMLED; }
 programmer       { yylval=NULL; return K_PROGRAMMER; }