You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by rh...@apache.org on 2013/01/23 16:11:22 UTC

svn commit: r1437449 - /subversion/trunk/subversion/libsvn_diff/diff_file.c

Author: rhuijben
Date: Wed Jan 23 15:11:22 2013
New Revision: 1437449

URL: http://svn.apache.org/viewvc?rev=1437449&view=rev
Log:
To resolve issue #3362, document the implementation of the file based unified
diff output processing by using a few more variables.

This resolves an edge case where we assumed that we could start a new hunk,
but there was not enough context to really start it. As a result the offsets
produced in the diff headers were not calculated correctly.

This doesn't fix the tests I added for this issue yet, because the memory
based unified diff has a similar but different bug for this edge case: It
leaves some of the unmodified context out of the final diff.

* subversion/libsvn_diff/diff_file.c
  (output_unified_diff_modified): Calculate the amount of context to use and
    use that as the base for the rest of the calculations. This avoids having
    to undo this step a few times.

Modified:
    subversion/trunk/subversion/libsvn_diff/diff_file.c

Modified: subversion/trunk/subversion/libsvn_diff/diff_file.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_diff/diff_file.c?rev=1437449&r1=1437448&r2=1437449&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_diff/diff_file.c (original)
+++ subversion/trunk/subversion/libsvn_diff/diff_file.c Wed Jan 23 15:11:22 2013
@@ -1643,46 +1643,74 @@ output_unified_diff_modified(void *baton
   apr_off_t latest_start, apr_off_t latest_length)
 {
   svn_diff__file_output_baton_t *output_baton = baton;
-  apr_off_t target_orig;
-  apr_off_t target_mod;
-  svn_boolean_t store_extra_context = FALSE;
-
-  target_orig = original_start >= SVN_DIFF__UNIFIED_CONTEXT_SIZE
-                   ? original_start - SVN_DIFF__UNIFIED_CONTEXT_SIZE : 0;
-  target_mod = modified_start;
-
-  /* If the changed ranges are far enough apart (no overlapping or connecting
-     context), flush the current hunk, initialize the next hunk and skip the
-     lines not in context.  Also do this when this is the first hunk.
-   */
-  if (output_baton->current_line[0] < target_orig
-      && (output_baton->hunk_start[0] + output_baton->hunk_length[0]
-          + SVN_DIFF__UNIFIED_CONTEXT_SIZE < target_orig
-          || output_baton->hunk_length[0] == 0))
-    {
-      SVN_ERR(output_unified_flush_hunk(output_baton));
+  apr_off_t context_prefix_length;
+  apr_off_t prev_context_end;
+  svn_boolean_t init_hunk = FALSE;
 
-      output_baton->hunk_start[0] = target_orig;
-      output_baton->hunk_start[1] = target_mod +(target_orig - original_start);
+  if (original_start > SVN_DIFF__UNIFIED_CONTEXT_SIZE)
+    context_prefix_length = SVN_DIFF__UNIFIED_CONTEXT_SIZE;
+  else
+    context_prefix_length = original_start;
 
-      store_extra_context = TRUE;
+  /* Calculate where the previous hunk will end if we would write it now
+     (including the necessary context at the end) */
+  if (output_baton->hunk_length[0] > 0 || output_baton->hunk_length[1] > 0)
+    {
+      prev_context_end = output_baton->hunk_start[0]
+                         + output_baton->hunk_length[0]
+                         + SVN_DIFF__UNIFIED_CONTEXT_SIZE;
     }
+  else
+    {
+      prev_context_end = -1;
+
+      if (output_baton->hunk_start[0] == 0
+          && (original_length > 0 || modified_length > 0))
+        init_hunk = TRUE;
+    }
+
+  /* If the changed range is far enough from the previous range, flush the current
+     hunk. */
+  {
+    apr_off_t new_hunk_start = (original_start - context_prefix_length);
+
+    if (output_baton->current_line[0] < new_hunk_start
+          && prev_context_end <= new_hunk_start)
+      {
+        SVN_ERR(output_unified_flush_hunk(output_baton));
+        init_hunk = TRUE;
+      }
+    else if (output_baton->hunk_length[0] > 0
+             || output_baton->hunk_length[1] > 0)
+      {
+        /* We extend the current hunk */
+
+
+        /* Original: Output the context preceding the changed range */
+        SVN_ERR(output_unified_diff_range(output_baton, 0 /* original */,
+                                          svn_diff__file_output_unified_context,
+                                          original_start));
+      }
+  }
 
   /* Original: Skip lines until we are at the beginning of the context we want
      to display */
   SVN_ERR(output_unified_diff_range(output_baton, 0 /* original */,
                                     svn_diff__file_output_unified_skip,
-                                    target_orig));
+                                    original_start - context_prefix_length));
 
-  /* Modified: Skip lines until we are at the start of the changed range */
-  SVN_ERR(output_unified_diff_range(output_baton, 1 /* modified */,
-                                    svn_diff__file_output_unified_skip,
-                                    target_mod));
+  /* Note that the above skip stores data for the show_c_function support below */
+
+  if (init_hunk)
+    {
+      SVN_ERR_ASSERT(output_baton->hunk_length[0] == 0
+                     && output_baton->hunk_length[1] == 0);
 
-  /* Note that these two skips might store data needed by the following
-     block, by processing the otherwise ignored lines */
+      output_baton->hunk_start[0] = original_start - context_prefix_length;
+      output_baton->hunk_start[1] = modified_start - context_prefix_length;
+    }
 
-  if (store_extra_context && output_baton->show_c_function)
+  if (init_hunk && output_baton->show_c_function)
     {
       apr_size_t p;
       const char *invalid_character;
@@ -1712,6 +1740,11 @@ output_unified_diff_modified(void *baton
         }
     }
 
+  /* Modified: Skip lines until we are at the start of the changed range */
+  SVN_ERR(output_unified_diff_range(output_baton, 1 /* modified */,
+                                    svn_diff__file_output_unified_skip,
+                                    modified_start));
+
   /* Original: Output the context preceding the changed range */
   SVN_ERR(output_unified_diff_range(output_baton, 0 /* original */,
                                     svn_diff__file_output_unified_context,