Enclose definitions in #if for POSIX-draft like API.
[gnulib.git] / lib / git-merge-changelog.c
index 022ac5c..524d5d3 100644 (file)
@@ -160,8 +160,24 @@ struct entry
 {
   char *string;
   size_t length;
+  /* Cache for the hash code.  */
+  bool hashcode_cached;
+  size_t hashcode;
 };
 
+/* Create an entry.
+   The memory region passed by the caller must of indefinite extent.  It is
+   *not* copied here.  */
+static struct entry *
+entry_create (char *string, size_t length)
+{
+  struct entry *result = XMALLOC (struct entry);
+  result->string = string;
+  result->length = length;
+  result->hashcode_cached = false;
+  return result;
+}
+
 /* Compare two entries for equality.  */
 static bool
 entry_equals (const void *elt1, const void *elt2)
@@ -170,22 +186,27 @@ entry_equals (const void *elt1, const void *elt2)
   const struct entry *entry2 = (const struct entry *) elt2;
   return entry1->length == entry2->length
         && memcmp (entry1->string, entry2->string, entry1->length) == 0;
-};
+}
 
 /* Return a hash code of the contents of a ChangeLog entry.  */
 static size_t
 entry_hashcode (const void *elt)
 {
-  const struct entry *entry = (const struct entry *) elt;
-  /* See http://www.haible.de/bruno/hashfunc.html.  */
-  const char *s;
-  size_t n;
-  size_t h = 0;
+  struct entry *entry = (struct entry *) elt;
+  if (!entry->hashcode_cached)
+    {
+      /* See http://www.haible.de/bruno/hashfunc.html.  */
+      const char *s;
+      size_t n;
+      size_t h = 0;
 
-  for (s = entry->string, n = entry->length; n > 0; s++, n--)
-    h = (unsigned char) *s + ((h << 9) | (h >> (sizeof (size_t) * CHAR_BIT - 9)));
+      for (s = entry->string, n = entry->length; n > 0; s++, n--)
+       h = (unsigned char) *s + ((h << 9) | (h >> (sizeof (size_t) * CHAR_BIT - 9)));
 
-  return h;
+      entry->hashcode = h;
+      entry->hashcode_cached = true;
+    }
+  return entry->hashcode;
 }
 
 /* Perform a fuzzy comparison of two ChangeLog entries.
@@ -282,9 +303,7 @@ read_changelog_file (const char *filename, struct changelog_file *result)
              }
          }
 
-       curr = XMALLOC (struct entry);
-       curr->string = start;
-       curr->length = ptr - start;
+       curr = entry_create (start, ptr - start);
        gl_list_add_last (result->entries_list, curr);
        gl_list_add_first (result->entries_reversed, curr);
 
@@ -735,19 +754,15 @@ try_split_merged_entry (const struct entry *old_entry,
   if (best_similarity < FSTRCMP_STRICTER_THRESHOLD)
     return false;
 
-  new_split[0] = XMALLOC (struct entry);
-  new_split[0]->string = new_entry->string;
-  new_split[0]->length = best_split_offset + 1;
+  new_split[0] = entry_create (new_entry->string, best_split_offset + 1);
 
-  new_split[1] = XMALLOC (struct entry);
   {
     size_t len1 = new_title_len;
     size_t len2 = new_entry->length - best_split_offset;
     char *combined = XNMALLOC (len1 + len2, char);
     memcpy (combined, new_entry->string, len1);
     memcpy (combined + len1, new_entry->string + best_split_offset, len2);
-    new_split[1]->string = combined;
-    new_split[1]->length = len1 + len2;
+    new_split[1] = entry_create (combined, len1 + len2);
   }
 
   return true;
@@ -793,7 +808,7 @@ conflict_write (FILE *fp, struct conflict *c)
 
 /* Long options.  */
 static const struct option long_options[] =
-{ 
+{
   { "help", no_argument, NULL, 'h' },
   { "split-merged-entry", no_argument, NULL, CHAR_MAX + 1 },
   { "version", no_argument, NULL, 'V' },
@@ -1242,7 +1257,8 @@ There is NO WARRANTY, to the extent permitted by law.\n\
                                                            result_entries_pointers[k],
                                                            changed_entry);
                                  }
-                               else
+                               else if (!entry_equals (ancestor_file.entries[i],
+                                                       changed_entry))
                                  {
                                    struct conflict *c = XMALLOC (struct conflict);
                                    c->num_old_entries = 1;
@@ -1322,7 +1338,10 @@ There is NO WARRANTY, to the extent permitted by law.\n\
                                  }
                                else
                                  {
-                                   struct conflict *c = XMALLOC (struct conflict);
+                                   struct conflict *c;
+                                   ASSERT (!entry_equals (ancestor_file.entries[i],
+                                                          changed_entry));
+                                   c = XMALLOC (struct conflict);
                                    c->num_old_entries = 1;
                                    c->old_entries =
                                      XNMALLOC (c->num_old_entries, struct entry *);
@@ -1384,7 +1403,10 @@ There is NO WARRANTY, to the extent permitted by law.\n\
                                      }
                                    else
                                      {
-                                       struct conflict *c = XMALLOC (struct conflict);
+                                       struct conflict *c;
+                                       ASSERT (!entry_equals (ancestor_file.entries[i],
+                                                              changed_entry));
+                                       c = XMALLOC (struct conflict);
                                        c->num_old_entries = 1;
                                        c->old_entries =
                                          XNMALLOC (c->num_old_entries, struct entry *);
@@ -1490,11 +1512,14 @@ There is NO WARRANTY, to the extent permitted by law.\n\
        for (i = 0; i < n; i++)
          conflict_write (fp, (struct conflict *) gl_list_get_at (result_conflicts, i));
       }
+      /* Output the modified and unmodified entries, in order.  */
       {
-       size_t n = gl_list_size (result_entries);
-       size_t i;
-       for (i = 0; i < n; i++)
-         entry_write (fp, (struct entry *) gl_list_get_at (result_entries, i));
+       gl_list_iterator_t iter = gl_list_iterator (result_entries);
+       const void *elt;
+       gl_list_node_t node;
+       while (gl_list_iterator_next (&iter, &elt, &node))
+         entry_write (fp, (struct entry *) elt);
+       gl_list_iterator_free (&iter);
       }
 
       if (fwriteerror (fp))