aboutsummaryrefslogtreecommitdiffstats
path: root/subversion/libsvn_diff
diff options
context:
space:
mode:
authorPeter Wemm <peter@FreeBSD.org>2015-10-12 08:54:49 +0000
committerPeter Wemm <peter@FreeBSD.org>2015-10-12 08:54:49 +0000
commitdc5d469d6574e9fb03bdd793658bb371315b306a (patch)
tree013c2e6845398e5a9ca4901dcc077769c7520e1d /subversion/libsvn_diff
parent58218291fa73a17020ef0447398e9e8a78f9e8c7 (diff)
downloadsrc-dc5d469d6574e9fb03bdd793658bb371315b306a.tar.gz
src-dc5d469d6574e9fb03bdd793658bb371315b306a.zip
Vendor import of subversion-1.9.2vendor/subversion/subversion-1.9.2
Notes
Notes: svn path=/vendor/subversion/dist/; revision=289177 svn path=/vendor/subversion/subversion-1.9.2/; revision=289178; tag=vendor/subversion/subversion-1.9.2
Diffstat (limited to 'subversion/libsvn_diff')
-rw-r--r--subversion/libsvn_diff/binary_diff.c221
-rw-r--r--subversion/libsvn_diff/deprecated.c175
-rw-r--r--subversion/libsvn_diff/diff4.c2
-rw-r--r--subversion/libsvn_diff/diff_file.c198
-rw-r--r--subversion/libsvn_diff/diff_memory.c204
-rw-r--r--subversion/libsvn_diff/lcs.c2
-rw-r--r--subversion/libsvn_diff/libsvn_diff.pc.in12
-rw-r--r--subversion/libsvn_diff/parse-diff.c223
-rw-r--r--subversion/libsvn_diff/util.c43
9 files changed, 829 insertions, 251 deletions
diff --git a/subversion/libsvn_diff/binary_diff.c b/subversion/libsvn_diff/binary_diff.c
new file mode 100644
index 000000000000..d42b2e53bf1b
--- /dev/null
+++ b/subversion/libsvn_diff/binary_diff.c
@@ -0,0 +1,221 @@
+/*
+ * binary_diff.c: handling of git like binary diffs
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ */
+
+#include <apr.h>
+
+#include "svn_pools.h"
+#include "svn_error.h"
+#include "svn_diff.h"
+#include "svn_types.h"
+
+/* Copies the data from ORIGINAL_STREAM to a temporary file, returning both
+ the original and compressed size. */
+static svn_error_t *
+create_compressed(apr_file_t **result,
+ svn_filesize_t *full_size,
+ svn_filesize_t *compressed_size,
+ svn_stream_t *original_stream,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ svn_stream_t *compressed;
+ svn_filesize_t bytes_read = 0;
+ apr_finfo_t finfo;
+ apr_size_t rd;
+
+ SVN_ERR(svn_io_open_uniquely_named(result, NULL, NULL, "diffgz",
+ NULL, svn_io_file_del_on_pool_cleanup,
+ result_pool, scratch_pool));
+
+ compressed = svn_stream_compressed(
+ svn_stream_from_aprfile2(*result, TRUE, scratch_pool),
+ scratch_pool);
+
+ if (original_stream)
+ do
+ {
+ char buffer[SVN_STREAM_CHUNK_SIZE];
+ rd = sizeof(buffer);
+
+ if (cancel_func)
+ SVN_ERR(cancel_func(cancel_baton));
+
+ SVN_ERR(svn_stream_read_full(original_stream, buffer, &rd));
+
+ bytes_read += rd;
+ SVN_ERR(svn_stream_write(compressed, buffer, &rd));
+ }
+ while(rd == SVN_STREAM_CHUNK_SIZE);
+ else
+ {
+ apr_size_t zero = 0;
+ SVN_ERR(svn_stream_write(compressed, NULL, &zero));
+ }
+
+ SVN_ERR(svn_stream_close(compressed)); /* Flush compression */
+
+ *full_size = bytes_read;
+ SVN_ERR(svn_io_file_info_get(&finfo, APR_FINFO_SIZE, *result, scratch_pool));
+ *compressed_size = finfo.size;
+
+ return SVN_NO_ERROR;
+}
+
+#define GIT_BASE85_CHUNKSIZE 52
+
+/* Git Base-85 table for write_literal */
+static const char b85str[] =
+ "0123456789"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "!#$%&()*+-;<=>?@^_`{|}~";
+
+/* Git length encoding table for write_literal */
+static const char b85lenstr[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz";
+
+/* Writes out a git-like literal output of the compressed data in
+ COMPRESSED_DATA to OUTPUT_STREAM, describing that its normal length is
+ UNCOMPRESSED_SIZE. */
+static svn_error_t *
+write_literal(svn_filesize_t uncompressed_size,
+ svn_stream_t *compressed_data,
+ svn_stream_t *output_stream,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ apr_pool_t *scratch_pool)
+{
+ apr_size_t rd;
+ SVN_ERR(svn_stream_seek(compressed_data, NULL)); /* Seek to start */
+
+ SVN_ERR(svn_stream_printf(output_stream, scratch_pool,
+ "literal %" SVN_FILESIZE_T_FMT APR_EOL_STR,
+ uncompressed_size));
+
+ do
+ {
+ char chunk[GIT_BASE85_CHUNKSIZE];
+ const unsigned char *next;
+ apr_size_t left;
+
+ rd = sizeof(chunk);
+
+ if (cancel_func)
+ SVN_ERR(cancel_func(cancel_baton));
+
+ SVN_ERR(svn_stream_read_full(compressed_data, chunk, &rd));
+
+ {
+ apr_size_t one = 1;
+ SVN_ERR(svn_stream_write(output_stream, &b85lenstr[rd-1], &one));
+ }
+
+ left = rd;
+ next = (void*)chunk;
+ while (left)
+ {
+ char five[5];
+ unsigned info = 0;
+ int n;
+ apr_size_t five_sz;
+
+ /* Push 4 bytes into the 32 bit info, when available */
+ for (n = 24; n >= 0 && left; n -= 8, next++, left--)
+ {
+ info |= (*next) << n;
+ }
+
+ /* Write out info as base85 */
+ for (n = 4; n >= 0; n--)
+ {
+ five[n] = b85str[info % 85];
+ info /= 85;
+ }
+
+ five_sz = 5;
+ SVN_ERR(svn_stream_write(output_stream, five, &five_sz));
+ }
+
+ SVN_ERR(svn_stream_puts(output_stream, APR_EOL_STR));
+ }
+ while (rd == GIT_BASE85_CHUNKSIZE);
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_diff_output_binary(svn_stream_t *output_stream,
+ svn_stream_t *original,
+ svn_stream_t *latest,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ apr_pool_t *scratch_pool)
+{
+ apr_file_t *original_apr;
+ svn_filesize_t original_full;
+ svn_filesize_t original_deflated;
+ apr_file_t *latest_apr;
+ svn_filesize_t latest_full;
+ svn_filesize_t latest_deflated;
+ apr_pool_t *subpool = svn_pool_create(scratch_pool);
+
+ SVN_ERR(create_compressed(&original_apr, &original_full, &original_deflated,
+ original, cancel_func, cancel_baton,
+ scratch_pool, subpool));
+ svn_pool_clear(subpool);
+
+ SVN_ERR(create_compressed(&latest_apr, &latest_full, &latest_deflated,
+ latest, cancel_func, cancel_baton,
+ scratch_pool, subpool));
+ svn_pool_clear(subpool);
+
+ SVN_ERR(svn_stream_puts(output_stream, "GIT binary patch" APR_EOL_STR));
+
+ /* ### git would first calculate if a git-delta original->latest would be
+ shorter than the zipped data. For now lets assume that it is not
+ and just dump the literal data */
+ SVN_ERR(write_literal(original_full,
+ svn_stream_from_aprfile2(original_apr, FALSE, subpool),
+ output_stream,
+ cancel_func, cancel_baton,
+ scratch_pool));
+ svn_pool_clear(subpool);
+ SVN_ERR(svn_stream_puts(output_stream, APR_EOL_STR));
+
+ /* ### git would first calculate if a git-delta latest->original would be
+ shorter than the zipped data. For now lets assume that it is not
+ and just dump the literal data */
+ SVN_ERR(write_literal(latest_full,
+ svn_stream_from_aprfile2(latest_apr, FALSE, subpool),
+ output_stream,
+ cancel_func, cancel_baton,
+ scratch_pool));
+ svn_pool_destroy(subpool);
+
+ SVN_ERR(svn_stream_puts(output_stream, APR_EOL_STR));
+
+ return SVN_NO_ERROR;
+}
diff --git a/subversion/libsvn_diff/deprecated.c b/subversion/libsvn_diff/deprecated.c
index 891ad5fa8fc0..b8dc097aaa03 100644
--- a/subversion/libsvn_diff/deprecated.c
+++ b/subversion/libsvn_diff/deprecated.c
@@ -143,6 +143,34 @@ wrap_diff_fns(svn_diff_fns2_t **diff_fns2,
/*** From diff_file.c ***/
+
+svn_error_t *
+svn_diff_file_output_unified3(svn_stream_t *output_stream,
+ svn_diff_t *diff,
+ const char *original_path,
+ const char *modified_path,
+ const char *original_header,
+ const char *modified_header,
+ const char *header_encoding,
+ const char *relative_to_dir,
+ svn_boolean_t show_c_function,
+ apr_pool_t *pool)
+{
+ return svn_error_trace(
+ svn_diff_file_output_unified4(output_stream,
+ diff,
+ original_path,
+ modified_path,
+ original_header,
+ modified_header,
+ header_encoding,
+ relative_to_dir,
+ show_c_function,
+ -1 /* context_size */,
+ NULL, NULL, /* cancel */
+ pool));
+}
+
svn_error_t *
svn_diff_file_output_unified2(svn_stream_t *output_stream,
svn_diff_t *diff,
@@ -243,6 +271,31 @@ svn_diff_file_output_merge(svn_stream_t *output_stream,
pool);
}
+svn_error_t *
+svn_diff_file_output_merge2(svn_stream_t *output_stream,
+ svn_diff_t *diff,
+ const char *original_path,
+ const char *modified_path,
+ const char *latest_path,
+ const char *conflict_original,
+ const char *conflict_modified,
+ const char *conflict_latest,
+ const char *conflict_separator,
+ svn_diff_conflict_display_style_t conflict_style,
+ apr_pool_t *pool)
+{
+ return svn_error_trace(svn_diff_file_output_merge3(output_stream,
+ diff, original_path,
+ modified_path,
+ latest_path,
+ conflict_original,
+ conflict_modified,
+ conflict_latest,
+ conflict_separator,
+ conflict_style,
+ NULL, NULL, /* cancel */
+ pool));
+}
/*** From diff.c ***/
svn_error_t *
@@ -287,3 +340,125 @@ svn_diff_diff4(svn_diff_t **diff,
wrap_diff_fns(&diff_fns2, &fwb, vtable, diff_baton, pool);
return svn_diff_diff4_2(diff, fwb, diff_fns2, pool);
}
+
+/*** From util.c ***/
+svn_error_t *
+svn_diff_output(svn_diff_t *diff,
+ void *output_baton,
+ const svn_diff_output_fns_t *output_fns)
+{
+ return svn_error_trace(svn_diff_output2(diff, output_baton, output_fns,
+ NULL, NULL /* cancel */));
+}
+
+/*** From diff_memory.c ***/
+svn_error_t *
+svn_diff_mem_string_output_merge(svn_stream_t *output_stream,
+ svn_diff_t *diff,
+ const svn_string_t *original,
+ const svn_string_t *modified,
+ const svn_string_t *latest,
+ const char *conflict_original,
+ const char *conflict_modified,
+ const char *conflict_latest,
+ const char *conflict_separator,
+ svn_boolean_t display_original_in_conflict,
+ svn_boolean_t display_resolved_conflicts,
+ apr_pool_t *pool)
+{
+ svn_diff_conflict_display_style_t style =
+ svn_diff_conflict_display_modified_latest;
+
+ if (display_resolved_conflicts)
+ style = svn_diff_conflict_display_resolved_modified_latest;
+
+ if (display_original_in_conflict)
+ style = svn_diff_conflict_display_modified_original_latest;
+
+ return svn_diff_mem_string_output_merge2(output_stream,
+ diff,
+ original,
+ modified,
+ latest,
+ conflict_original,
+ conflict_modified,
+ conflict_latest,
+ conflict_separator,
+ style,
+ pool);
+}
+
+svn_error_t *
+svn_diff_mem_string_output_merge2(svn_stream_t *output_stream,
+ svn_diff_t *diff,
+ const svn_string_t *original,
+ const svn_string_t *modified,
+ const svn_string_t *latest,
+ const char *conflict_original,
+ const char *conflict_modified,
+ const char *conflict_latest,
+ const char *conflict_separator,
+ svn_diff_conflict_display_style_t style,
+ apr_pool_t *pool)
+{
+ return svn_error_trace(svn_diff_mem_string_output_merge3(output_stream, diff,
+ original,
+ modified, latest,
+ conflict_original,
+ conflict_modified,
+ conflict_latest,
+ conflict_separator,
+ style,
+ /* no cancelation */
+ NULL, NULL,
+ pool));
+}
+
+svn_error_t *
+svn_diff_mem_string_output_unified(svn_stream_t *output_stream,
+ svn_diff_t *diff,
+ const char *original_header,
+ const char *modified_header,
+ const char *header_encoding,
+ const svn_string_t *original,
+ const svn_string_t *modified,
+ apr_pool_t *pool)
+{
+ return svn_error_trace(svn_diff_mem_string_output_unified2(output_stream,
+ diff,
+ TRUE,
+ NULL,
+ original_header,
+ modified_header,
+ header_encoding,
+ original,
+ modified,
+ pool));
+}
+
+svn_error_t *
+svn_diff_mem_string_output_unified2(svn_stream_t *output_stream,
+ svn_diff_t *diff,
+ svn_boolean_t with_diff_header,
+ const char *hunk_delimiter,
+ const char *original_header,
+ const char *modified_header,
+ const char *header_encoding,
+ const svn_string_t *original,
+ const svn_string_t *modified,
+ apr_pool_t *pool)
+{
+ return svn_error_trace(svn_diff_mem_string_output_unified3(output_stream,
+ diff,
+ with_diff_header,
+ hunk_delimiter,
+ original_header,
+ modified_header,
+ header_encoding,
+ original,
+ modified,
+ -1 /* context */,
+ /* cancel */
+ NULL, NULL,
+ pool));
+}
diff --git a/subversion/libsvn_diff/diff4.c b/subversion/libsvn_diff/diff4.c
index 9f3cb8cd2c93..1ecbb38e8e29 100644
--- a/subversion/libsvn_diff/diff4.c
+++ b/subversion/libsvn_diff/diff4.c
@@ -270,7 +270,7 @@ svn_diff_diff4_2(svn_diff_t **diff,
}
/* Get the lcs for common ancestor - original
- * Do reverse adjustements
+ * Do reverse adjustments
*/
lcs_adjust = svn_diff__lcs(position_list[3], position_list[2],
token_counts[3], token_counts[2],
diff --git a/subversion/libsvn_diff/diff_file.c b/subversion/libsvn_diff/diff_file.c
index 830552ac46ff..f54522e7c9c6 100644
--- a/subversion/libsvn_diff/diff_file.c
+++ b/subversion/libsvn_diff/diff_file.c
@@ -31,6 +31,8 @@
#include <apr_mmap.h>
#include <apr_getopt.h>
+#include <assert.h>
+
#include "svn_error.h"
#include "svn_diff.h"
#include "svn_types.h"
@@ -137,16 +139,16 @@ datasource_to_index(svn_diff_datasource_e datasource)
* *LENGTH. The actual bytes read are stored in *LENGTH on return.
*/
static APR_INLINE svn_error_t *
-read_chunk(apr_file_t *file, const char *path,
+read_chunk(apr_file_t *file,
char *buffer, apr_off_t length,
- apr_off_t offset, apr_pool_t *pool)
+ apr_off_t offset, apr_pool_t *scratch_pool)
{
/* XXX: The final offset may not be the one we asked for.
* XXX: Check.
*/
- SVN_ERR(svn_io_file_seek(file, APR_SET, &offset, pool));
+ SVN_ERR(svn_io_file_seek(file, APR_SET, &offset, scratch_pool));
return svn_io_file_read_full2(file, buffer, (apr_size_t) length,
- NULL, NULL, pool);
+ NULL, NULL, scratch_pool);
}
@@ -286,7 +288,7 @@ increment_chunk(struct file_info *file, apr_pool_t *pool)
file->chunk++;
length = file->chunk == last_chunk ?
offset_in_chunk(file->size) : CHUNK_SIZE;
- SVN_ERR(read_chunk(file->file, file->path, file->buffer,
+ SVN_ERR(read_chunk(file->file, file->buffer,
length, chunk_to_offset(file->chunk),
pool));
file->endp = file->buffer + length;
@@ -313,7 +315,7 @@ decrement_chunk(struct file_info *file, apr_pool_t *pool)
{
/* Read previous chunk and reset pointers. */
file->chunk--;
- SVN_ERR(read_chunk(file->file, file->path, file->buffer,
+ SVN_ERR(read_chunk(file->file, file->buffer,
CHUNK_SIZE, chunk_to_offset(file->chunk),
pool));
file->endp = file->buffer + CHUNK_SIZE;
@@ -542,7 +544,6 @@ find_identical_suffix(apr_off_t *suffix_lines, struct file_info file[],
int suffix_lines_to_keep = SUFFIX_LINES_TO_KEEP;
svn_boolean_t is_match;
apr_off_t lines = 0;
- svn_boolean_t had_cr;
svn_boolean_t had_nl;
apr_size_t i;
@@ -573,7 +574,7 @@ find_identical_suffix(apr_off_t *suffix_lines, struct file_info file[],
/* There is at least more than 1 chunk,
so allocate full chunk size buffer */
file_for_suffix[i].buffer = apr_palloc(pool, CHUNK_SIZE);
- SVN_ERR(read_chunk(file_for_suffix[i].file, file_for_suffix[i].path,
+ SVN_ERR(read_chunk(file_for_suffix[i].file,
file_for_suffix[i].buffer, length[i],
chunk_to_offset(file_for_suffix[i].chunk),
pool));
@@ -646,11 +647,10 @@ find_identical_suffix(apr_off_t *suffix_lines, struct file_info file[],
min_curp[0] += suffix_min_offset0;
/* Scan quickly by reading with machine-word granularity. */
- for (i = 0, can_read_word = TRUE; i < file_len; i++)
- can_read_word = can_read_word
- && ( (file_for_suffix[i].curp + 1
- - sizeof(apr_uintptr_t))
- > min_curp[i]);
+ for (i = 0, can_read_word = TRUE; can_read_word && i < file_len; i++)
+ can_read_word = ((file_for_suffix[i].curp + 1 - sizeof(apr_uintptr_t))
+ > min_curp[i]);
+
while (can_read_word)
{
apr_uintptr_t chunk;
@@ -664,9 +664,8 @@ find_identical_suffix(apr_off_t *suffix_lines, struct file_info file[],
if (contains_eol(chunk))
break;
- for (i = 1, is_match = TRUE; i < file_len; i++)
- is_match = is_match
- && ( chunk
+ for (i = 1, is_match = TRUE; is_match && i < file_len; i++)
+ is_match = (chunk
== *(const apr_uintptr_t *)
(file_for_suffix[i].curp + 1
- sizeof(apr_uintptr_t)));
@@ -685,7 +684,6 @@ find_identical_suffix(apr_off_t *suffix_lines, struct file_info file[],
/* We skipped some bytes, so there are no closing EOLs */
had_nl = FALSE;
- had_cr = FALSE;
}
/* The > min_curp[i] check leaves at least one final byte for checking
@@ -712,7 +710,7 @@ find_identical_suffix(apr_off_t *suffix_lines, struct file_info file[],
one file reaches its end. */
do
{
- had_cr = FALSE;
+ svn_boolean_t had_cr = FALSE;
while (!is_one_at_eof(file_for_suffix, file_len)
&& *file_for_suffix[0].curp != '\n'
&& *file_for_suffix[0].curp != '\r')
@@ -803,7 +801,7 @@ datasources_open(void *baton,
file->size = finfo[i].size;
length[i] = finfo[i].size > CHUNK_SIZE ? CHUNK_SIZE : finfo[i].size;
file->buffer = apr_palloc(file_baton->pool, (apr_size_t) length[i]);
- SVN_ERR(read_chunk(file->file, file->path, file->buffer,
+ SVN_ERR(read_chunk(file->file, file->buffer,
length[i], 0, file_baton->pool));
file->endp = file->buffer + length[i];
file->curp = file->buffer;
@@ -969,9 +967,9 @@ datasource_get_next_token(apr_uint32_t *hash, void **token, void *baton,
function.
When changing things here, make sure the whitespace settings are
- applied, or we mught not reach the exact suffix boundary as token
+ applied, or we might not reach the exact suffix boundary as token
boundary. */
- SVN_ERR(read_chunk(file->file, file->path,
+ SVN_ERR(read_chunk(file->file,
curp, length,
chunk_to_offset(file->chunk),
file_baton->pool));
@@ -1113,7 +1111,6 @@ token_compare(void *baton, void *token1, void *token2, int *compare)
COMPARE_CHUNK_SIZE : raw_length[i];
SVN_ERR(read_chunk(file[i]->file,
- file[i]->path,
bufp[i], length[i], offset[i],
file_baton->pool));
offset[i] += length[i];
@@ -1196,13 +1193,18 @@ static const apr_getopt_option_t diff_options[] =
/* ### For compatibility; we don't support the argument to -u, because
* ### we don't have optional argument support. */
{ "unified", 'u', 0, NULL },
+ { "context", 'U', 1, NULL },
{ NULL, 0, 0, NULL }
};
svn_diff_file_options_t *
svn_diff_file_options_create(apr_pool_t *pool)
{
- return apr_pcalloc(pool, sizeof(svn_diff_file_options_t));
+ svn_diff_file_options_t * opts = apr_pcalloc(pool, sizeof(*opts));
+
+ opts->context_size = SVN_DIFF__UNIFIED_CONTEXT_SIZE;
+
+ return opts;
}
/* A baton for use with opt_parsing_error_func(). */
@@ -1248,7 +1250,7 @@ svn_diff_file_options_parse(svn_diff_file_options_t *options,
opt_parsing_error_baton.pool = pool;
argv[0] = "";
- memcpy((void *) (argv + 1), args->elts, sizeof(char*) * args->nelts);
+ memcpy(argv + 1, args->elts, sizeof(char*) * args->nelts);
argv[args->nelts + 1] = NULL;
apr_getopt_init(&os, pool, args->nelts + 1, argv);
@@ -1291,6 +1293,9 @@ svn_diff_file_options_parse(svn_diff_file_options_t *options,
case 'p':
options->show_c_function = TRUE;
break;
+ case 'U':
+ SVN_ERR(svn_cstring_atoi(&options->context_size, opt_arg));
+ break;
default:
break;
}
@@ -1410,6 +1415,8 @@ typedef struct svn_diff__file_output_baton_t
/* Extra context for the current hunk. */
char hunk_extra_context[SVN_DIFF__EXTRA_CONTEXT_LENGTH + 1];
+ int context_size;
+
apr_pool_t *pool;
} svn_diff__file_output_baton_t;
@@ -1615,7 +1622,7 @@ output_unified_flush_hunk(svn_diff__file_output_baton_t *baton)
}
target_line = baton->hunk_start[0] + baton->hunk_length[0]
- + SVN_DIFF__UNIFIED_CONTEXT_SIZE;
+ + baton->context_size;
/* Add trailing context to the hunk */
SVN_ERR(output_unified_diff_range(baton, 0 /* original */,
@@ -1666,8 +1673,8 @@ output_unified_diff_modified(void *baton,
apr_off_t prev_context_end;
svn_boolean_t init_hunk = FALSE;
- if (original_start > SVN_DIFF__UNIFIED_CONTEXT_SIZE)
- context_prefix_length = SVN_DIFF__UNIFIED_CONTEXT_SIZE;
+ if (original_start > output_baton->context_size)
+ context_prefix_length = output_baton->context_size;
else
context_prefix_length = original_start;
@@ -1677,7 +1684,7 @@ output_unified_diff_modified(void *baton,
{
prev_context_end = output_baton->hunk_start[0]
+ output_baton->hunk_length[0]
- + SVN_DIFF__UNIFIED_CONTEXT_SIZE;
+ + output_baton->context_size;
}
else
{
@@ -1815,7 +1822,7 @@ static const svn_diff_output_fns_t svn_diff__file_output_unified_vtable =
};
svn_error_t *
-svn_diff_file_output_unified3(svn_stream_t *output_stream,
+svn_diff_file_output_unified4(svn_stream_t *output_stream,
svn_diff_t *diff,
const char *original_path,
const char *modified_path,
@@ -1824,6 +1831,9 @@ svn_diff_file_output_unified3(svn_stream_t *output_stream,
const char *header_encoding,
const char *relative_to_dir,
svn_boolean_t show_c_function,
+ int context_size,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
apr_pool_t *pool)
{
if (svn_diff_contains_diffs(diff))
@@ -1840,6 +1850,8 @@ svn_diff_file_output_unified3(svn_stream_t *output_stream,
baton.hunk = svn_stringbuf_create_empty(pool);
baton.show_c_function = show_c_function;
baton.extra_context = svn_stringbuf_create_empty(pool);
+ baton.context_size = (context_size >= 0) ? context_size
+ : SVN_DIFF__UNIFIED_CONTEXT_SIZE;
if (show_c_function)
{
@@ -1918,8 +1930,9 @@ svn_diff_file_output_unified3(svn_stream_t *output_stream,
original_header, modified_header,
pool));
- SVN_ERR(svn_diff_output(diff, &baton,
- &svn_diff__file_output_unified_vtable));
+ SVN_ERR(svn_diff_output2(diff, &baton,
+ &svn_diff__file_output_unified_vtable,
+ cancel_func, cancel_baton));
SVN_ERR(output_unified_flush_hunk(&baton));
for (i = 0; i < 2; i++)
@@ -1939,8 +1952,9 @@ svn_diff_file_output_unified3(svn_stream_t *output_stream,
*pointers! */
typedef struct context_saver_t {
svn_stream_t *stream;
- const char *data[SVN_DIFF__UNIFIED_CONTEXT_SIZE];
- apr_size_t len[SVN_DIFF__UNIFIED_CONTEXT_SIZE];
+ int context_size;
+ const char **data; /* const char *data[context_size] */
+ apr_size_t *len; /* apr_size_t len[context_size] */
apr_size_t next_slot;
apr_size_t total_written;
} context_saver_t;
@@ -1952,10 +1966,14 @@ context_saver_stream_write(void *baton,
apr_size_t *len)
{
context_saver_t *cs = baton;
- cs->data[cs->next_slot] = data;
- cs->len[cs->next_slot] = *len;
- cs->next_slot = (cs->next_slot + 1) % SVN_DIFF__UNIFIED_CONTEXT_SIZE;
- cs->total_written++;
+
+ if (cs->context_size > 0)
+ {
+ cs->data[cs->next_slot] = data;
+ cs->len[cs->next_slot] = *len;
+ cs->next_slot = (cs->next_slot + 1) % cs->context_size;
+ cs->total_written++;
+ }
return SVN_NO_ERROR;
}
@@ -1980,6 +1998,11 @@ typedef struct svn_diff3__file_output_baton_t
const char *marker_eol;
svn_diff_conflict_display_style_t conflict_style;
+ int context_size;
+
+ /* cancel support */
+ svn_cancel_func_t cancel_func;
+ void *cancel_baton;
/* The rest of the fields are for
svn_diff_conflict_display_only_conflicts only. Note that for
@@ -1999,9 +2022,9 @@ flush_context_saver(context_saver_t *cs,
svn_stream_t *output_stream)
{
int i;
- for (i = 0; i < SVN_DIFF__UNIFIED_CONTEXT_SIZE; i++)
+ for (i = 0; i < cs->context_size; i++)
{
- apr_size_t slot = (i + cs->next_slot) % SVN_DIFF__UNIFIED_CONTEXT_SIZE;
+ apr_size_t slot = (i + cs->next_slot) % cs->context_size;
if (cs->data[slot])
{
apr_size_t len = cs->len[slot];
@@ -2016,6 +2039,8 @@ make_context_saver(svn_diff3__file_output_baton_t *fob)
{
context_saver_t *cs;
+ assert(fob->context_size > 0); /* Or nothing to save */
+
svn_pool_clear(fob->pool);
cs = apr_pcalloc(fob->pool, sizeof(*cs));
cs->stream = svn_stream_empty(fob->pool);
@@ -2023,10 +2048,13 @@ make_context_saver(svn_diff3__file_output_baton_t *fob)
svn_stream_set_write(cs->stream, context_saver_stream_write);
fob->context_saver = cs;
fob->output_stream = cs->stream;
+ cs->context_size = fob->context_size;
+ cs->data = apr_pcalloc(fob->pool, sizeof(*cs->data) * cs->context_size);
+ cs->len = apr_pcalloc(fob->pool, sizeof(*cs->len) * cs->context_size);
}
-/* A stream which prints SVN_DIFF__UNIFIED_CONTEXT_SIZE lines to
+/* A stream which prints LINES_TO_PRINT (based on context size) lines to
BATON->REAL_OUTPUT_STREAM, and then changes BATON->OUTPUT_STREAM to
a context_saver; used for *trailing* context. */
@@ -2061,7 +2089,7 @@ make_trailing_context_printer(svn_diff3__file_output_baton_t *btn)
svn_pool_clear(btn->pool);
tcp = apr_pcalloc(btn->pool, sizeof(*tcp));
- tcp->lines_to_print = SVN_DIFF__UNIFIED_CONTEXT_SIZE;
+ tcp->lines_to_print = btn->context_size;
tcp->fob = btn;
s = svn_stream_empty(btn->pool);
svn_stream_set_baton(s, tcp);
@@ -2191,7 +2219,25 @@ static const svn_diff_output_fns_t svn_diff3__file_output_vtable =
output_conflict
};
+static svn_error_t *
+output_conflict_with_context_marker(svn_diff3__file_output_baton_t *btn,
+ const char *label,
+ apr_off_t start,
+ apr_off_t length)
+{
+ if (length == 1)
+ SVN_ERR(svn_stream_printf(btn->output_stream, btn->pool,
+ "%s (%" APR_OFF_T_FMT ")",
+ label, start + 1));
+ else
+ SVN_ERR(svn_stream_printf(btn->output_stream, btn->pool,
+ "%s (%" APR_OFF_T_FMT ",%" APR_OFF_T_FMT ")",
+ label, start + 1, length));
+ SVN_ERR(output_marker_eol(btn));
+
+ return SVN_NO_ERROR;
+}
static svn_error_t *
output_conflict_with_context(svn_diff3__file_output_baton_t *btn,
@@ -2206,7 +2252,7 @@ output_conflict_with_context(svn_diff3__file_output_baton_t *btn,
trailing context)? If so, flush it. */
if (btn->output_stream == btn->context_saver->stream)
{
- if (btn->context_saver->total_written > SVN_DIFF__UNIFIED_CONTEXT_SIZE)
+ if (btn->context_saver->total_written > btn->context_size)
SVN_ERR(svn_stream_puts(btn->real_output_stream, "@@\n"));
SVN_ERR(flush_context_saver(btn->context_saver, btn->real_output_stream));
}
@@ -2215,34 +2261,19 @@ output_conflict_with_context(svn_diff3__file_output_baton_t *btn,
btn->output_stream = btn->real_output_stream;
/* Output the conflict itself. */
- SVN_ERR(svn_stream_printf(btn->output_stream, btn->pool,
- (modified_length == 1
- ? "%s (%" APR_OFF_T_FMT ")"
- : "%s (%" APR_OFF_T_FMT ",%" APR_OFF_T_FMT ")"),
- btn->conflict_modified,
- modified_start + 1, modified_length));
- SVN_ERR(output_marker_eol(btn));
+ SVN_ERR(output_conflict_with_context_marker(btn, btn->conflict_modified,
+ modified_start, modified_length));
SVN_ERR(output_hunk(btn, 1/*modified*/, modified_start, modified_length));
- SVN_ERR(svn_stream_printf(btn->output_stream, btn->pool,
- (original_length == 1
- ? "%s (%" APR_OFF_T_FMT ")"
- : "%s (%" APR_OFF_T_FMT ",%" APR_OFF_T_FMT ")"),
- btn->conflict_original,
- original_start + 1, original_length));
- SVN_ERR(output_marker_eol(btn));
+ SVN_ERR(output_conflict_with_context_marker(btn, btn->conflict_original,
+ original_start, original_length));
SVN_ERR(output_hunk(btn, 0/*original*/, original_start, original_length));
SVN_ERR(svn_stream_printf(btn->output_stream, btn->pool,
"%s%s", btn->conflict_separator, btn->marker_eol));
SVN_ERR(output_hunk(btn, 2/*latest*/, latest_start, latest_length));
- SVN_ERR(svn_stream_printf(btn->output_stream, btn->pool,
- (latest_length == 1
- ? "%s (%" APR_OFF_T_FMT ")"
- : "%s (%" APR_OFF_T_FMT ",%" APR_OFF_T_FMT ")"),
- btn->conflict_latest,
- latest_start + 1, latest_length));
- SVN_ERR(output_marker_eol(btn));
+ SVN_ERR(output_conflict_with_context_marker(btn, btn->conflict_latest,
+ latest_start, latest_length));
/* Go into print-trailing-context mode instead. */
make_trailing_context_printer(btn);
@@ -2271,8 +2302,10 @@ output_conflict(void *baton,
if (style == svn_diff_conflict_display_resolved_modified_latest)
{
if (diff)
- return svn_diff_output(diff, baton,
- &svn_diff3__file_output_vtable);
+ return svn_diff_output2(diff, baton,
+ &svn_diff3__file_output_vtable,
+ file_baton->cancel_func,
+ file_baton->cancel_baton);
else
style = svn_diff_conflict_display_modified_latest;
}
@@ -2315,7 +2348,7 @@ output_conflict(void *baton,
}
svn_error_t *
-svn_diff_file_output_merge2(svn_stream_t *output_stream,
+svn_diff_file_output_merge3(svn_stream_t *output_stream,
svn_diff_t *diff,
const char *original_path,
const char *modified_path,
@@ -2325,7 +2358,9 @@ svn_diff_file_output_merge2(svn_stream_t *output_stream,
const char *conflict_latest,
const char *conflict_separator,
svn_diff_conflict_display_style_t style,
- apr_pool_t *pool)
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ apr_pool_t *scratch_pool)
{
svn_diff3__file_output_baton_t baton;
apr_file_t *file[3];
@@ -2338,9 +2373,10 @@ svn_diff_file_output_merge2(svn_stream_t *output_stream,
(style == svn_diff_conflict_display_only_conflicts);
memset(&baton, 0, sizeof(baton));
+ baton.context_size = SVN_DIFF__UNIFIED_CONTEXT_SIZE;
if (conflicts_only)
{
- baton.pool = svn_pool_create(pool);
+ baton.pool = svn_pool_create(scratch_pool);
make_context_saver(&baton);
baton.real_output_stream = output_stream;
}
@@ -2351,22 +2387,22 @@ svn_diff_file_output_merge2(svn_stream_t *output_stream,
baton.path[2] = latest_path;
SVN_ERR(svn_utf_cstring_from_utf8(&baton.conflict_modified,
conflict_modified ? conflict_modified
- : apr_psprintf(pool, "<<<<<<< %s",
+ : apr_psprintf(scratch_pool, "<<<<<<< %s",
modified_path),
- pool));
+ scratch_pool));
SVN_ERR(svn_utf_cstring_from_utf8(&baton.conflict_original,
conflict_original ? conflict_original
- : apr_psprintf(pool, "||||||| %s",
+ : apr_psprintf(scratch_pool, "||||||| %s",
original_path),
- pool));
+ scratch_pool));
SVN_ERR(svn_utf_cstring_from_utf8(&baton.conflict_separator,
conflict_separator ? conflict_separator
- : "=======", pool));
+ : "=======", scratch_pool));
SVN_ERR(svn_utf_cstring_from_utf8(&baton.conflict_latest,
conflict_latest ? conflict_latest
- : apr_psprintf(pool, ">>>>>>> %s",
+ : apr_psprintf(scratch_pool, ">>>>>>> %s",
latest_path),
- pool));
+ scratch_pool));
baton.conflict_style = style;
@@ -2377,7 +2413,7 @@ svn_diff_file_output_merge2(svn_stream_t *output_stream,
SVN_ERR(map_or_read_file(&file[idx],
MMAP_T_ARG(mm[idx])
&baton.buffer[idx], &size,
- baton.path[idx], pool));
+ baton.path[idx], scratch_pool));
baton.curp[idx] = baton.buffer[idx];
baton.endp[idx] = baton.buffer[idx];
@@ -2395,8 +2431,12 @@ svn_diff_file_output_merge2(svn_stream_t *output_stream,
eol = APR_EOL_STR;
baton.marker_eol = eol;
- SVN_ERR(svn_diff_output(diff, &baton,
- &svn_diff3__file_output_vtable));
+ baton.cancel_func = cancel_func;
+ baton.cancel_baton = cancel_baton;
+
+ SVN_ERR(svn_diff_output2(diff, &baton,
+ &svn_diff3__file_output_vtable,
+ cancel_func, cancel_baton));
for (idx = 0; idx < 3; idx++)
{
@@ -2414,7 +2454,7 @@ svn_diff_file_output_merge2(svn_stream_t *output_stream,
if (file[idx])
{
- SVN_ERR(svn_io_file_close(file[idx], pool));
+ SVN_ERR(svn_io_file_close(file[idx], scratch_pool));
}
}
diff --git a/subversion/libsvn_diff/diff_memory.c b/subversion/libsvn_diff/diff_memory.c
index 00f4c7fd4184..d9d800d7162c 100644
--- a/subversion/libsvn_diff/diff_memory.c
+++ b/subversion/libsvn_diff/diff_memory.c
@@ -356,6 +356,8 @@ typedef struct unified_output_baton_t
source_tokens_t sources[2]; /* 0 == original; 1 == modified */
apr_off_t current_token[2]; /* current token per source */
+ int context_size;
+
/* Cached markers, in header_encoding,
indexed using unified_output_e */
const char *prefix_str[3];
@@ -461,7 +463,7 @@ output_unified_flush_hunk(output_baton_t *baton,
/* Write the trailing context */
target_token = baton->hunk_start[0] + baton->hunk_length[0]
- + SVN_DIFF__UNIFIED_CONTEXT_SIZE;
+ + baton->context_size;
SVN_ERR(output_unified_token_range(baton, 0 /*original*/,
unified_output_context,
target_token));
@@ -515,8 +517,8 @@ output_unified_diff_modified(void *baton,
apr_off_t prev_context_end;
svn_boolean_t init_hunk = FALSE;
- if (original_start > SVN_DIFF__UNIFIED_CONTEXT_SIZE)
- context_prefix_length = SVN_DIFF__UNIFIED_CONTEXT_SIZE;
+ if (original_start > output_baton->context_size)
+ context_prefix_length = output_baton->context_size;
else
context_prefix_length = original_start;
@@ -526,7 +528,7 @@ output_unified_diff_modified(void *baton,
{
prev_context_end = output_baton->hunk_start[0]
+ output_baton->hunk_length[0]
- + SVN_DIFF__UNIFIED_CONTEXT_SIZE;
+ + output_baton->context_size;
}
else
{
@@ -608,7 +610,7 @@ static const svn_diff_output_fns_t mem_output_unified_vtable =
svn_error_t *
-svn_diff_mem_string_output_unified2(svn_stream_t *output_stream,
+svn_diff_mem_string_output_unified3(svn_stream_t *output_stream,
svn_diff_t *diff,
svn_boolean_t with_diff_header,
const char *hunk_delimiter,
@@ -617,7 +619,10 @@ svn_diff_mem_string_output_unified2(svn_stream_t *output_stream,
const char *header_encoding,
const svn_string_t *original,
const svn_string_t *modified,
- apr_pool_t *pool)
+ int context_size,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ apr_pool_t *scratch_pool)
{
if (svn_diff_contains_diffs(diff))
@@ -626,37 +631,40 @@ svn_diff_mem_string_output_unified2(svn_stream_t *output_stream,
memset(&baton, 0, sizeof(baton));
baton.output_stream = output_stream;
- baton.pool = svn_pool_create(pool);
+ baton.pool = svn_pool_create(scratch_pool);
baton.header_encoding = header_encoding;
- baton.hunk = svn_stringbuf_create_empty(pool);
+ baton.hunk = svn_stringbuf_create_empty(scratch_pool);
baton.hunk_delimiter = hunk_delimiter;
baton.no_newline_string
= (hunk_delimiter == NULL || strcmp(hunk_delimiter, "##") != 0)
? APR_EOL_STR SVN_DIFF__NO_NEWLINE_AT_END_OF_FILE APR_EOL_STR
: APR_EOL_STR SVN_DIFF__NO_NEWLINE_AT_END_OF_PROPERTY APR_EOL_STR;
+ baton.context_size = context_size >= 0 ? context_size
+ : SVN_DIFF__UNIFIED_CONTEXT_SIZE;
SVN_ERR(svn_utf_cstring_from_utf8_ex2
(&(baton.prefix_str[unified_output_context]), " ",
- header_encoding, pool));
+ header_encoding, scratch_pool));
SVN_ERR(svn_utf_cstring_from_utf8_ex2
(&(baton.prefix_str[unified_output_delete]), "-",
- header_encoding, pool));
+ header_encoding, scratch_pool));
SVN_ERR(svn_utf_cstring_from_utf8_ex2
(&(baton.prefix_str[unified_output_insert]), "+",
- header_encoding, pool));
+ header_encoding, scratch_pool));
- fill_source_tokens(&baton.sources[0], original, pool);
- fill_source_tokens(&baton.sources[1], modified, pool);
+ fill_source_tokens(&baton.sources[0], original, scratch_pool);
+ fill_source_tokens(&baton.sources[1], modified, scratch_pool);
if (with_diff_header)
{
SVN_ERR(svn_diff__unidiff_write_header(
output_stream, header_encoding,
- original_header, modified_header, pool));
+ original_header, modified_header, scratch_pool));
}
- SVN_ERR(svn_diff_output(diff, &baton,
- &mem_output_unified_vtable));
+ SVN_ERR(svn_diff_output2(diff, &baton,
+ &mem_output_unified_vtable,
+ cancel_func, cancel_baton));
SVN_ERR(output_unified_flush_hunk(&baton, hunk_delimiter));
@@ -666,28 +674,6 @@ svn_diff_mem_string_output_unified2(svn_stream_t *output_stream,
return SVN_NO_ERROR;
}
-svn_error_t *
-svn_diff_mem_string_output_unified(svn_stream_t *output_stream,
- svn_diff_t *diff,
- const char *original_header,
- const char *modified_header,
- const char *header_encoding,
- const svn_string_t *original,
- const svn_string_t *modified,
- apr_pool_t *pool)
-{
- SVN_ERR(svn_diff_mem_string_output_unified2(output_stream,
- diff,
- TRUE,
- NULL,
- original_header,
- modified_header,
- header_encoding,
- original,
- modified,
- pool));
- return SVN_NO_ERROR;
-}
@@ -698,8 +684,9 @@ svn_diff_mem_string_output_unified(svn_stream_t *output_stream,
*pointers! */
typedef struct context_saver_t {
svn_stream_t *stream;
- const char *data[SVN_DIFF__UNIFIED_CONTEXT_SIZE];
- apr_size_t len[SVN_DIFF__UNIFIED_CONTEXT_SIZE];
+ int context_size;
+ const char **data; /* const char *data[context_size] */
+ apr_size_t *len; /* apr_size_t len[context_size] */
apr_size_t next_slot;
apr_size_t total_written;
} context_saver_t;
@@ -713,7 +700,7 @@ context_saver_stream_write(void *baton,
context_saver_t *cs = baton;
cs->data[cs->next_slot] = data;
cs->len[cs->next_slot] = *len;
- cs->next_slot = (cs->next_slot + 1) % SVN_DIFF__UNIFIED_CONTEXT_SIZE;
+ cs->next_slot = (cs->next_slot + 1) % cs->context_size;
cs->total_written++;
return SVN_NO_ERROR;
}
@@ -733,6 +720,11 @@ typedef struct merge_output_baton_t
const char *marker_eol;
svn_diff_conflict_display_style_t conflict_style;
+ int context_size;
+
+ /* cancel support */
+ svn_cancel_func_t cancel_func;
+ void *cancel_baton;
/* The rest of the fields are for
svn_diff_conflict_display_only_conflicts only. Note that for
@@ -753,9 +745,9 @@ flush_context_saver(context_saver_t *cs,
svn_stream_t *output_stream)
{
int i;
- for (i = 0; i < SVN_DIFF__UNIFIED_CONTEXT_SIZE; i++)
+ for (i = 0; i < cs->context_size; i++)
{
- apr_size_t slot = (i + cs->next_slot) % SVN_DIFF__UNIFIED_CONTEXT_SIZE;
+ apr_size_t slot = (i + cs->next_slot) % cs->context_size;
if (cs->data[slot])
{
apr_size_t len = cs->len[slot];
@@ -771,6 +763,8 @@ make_context_saver(merge_output_baton_t *mob)
{
context_saver_t *cs;
+ assert(mob->context_size > 0); /* Or nothing to save */
+
svn_pool_clear(mob->pool);
cs = apr_pcalloc(mob->pool, sizeof(*cs));
cs->stream = svn_stream_empty(mob->pool);
@@ -778,10 +772,13 @@ make_context_saver(merge_output_baton_t *mob)
svn_stream_set_write(cs->stream, context_saver_stream_write);
mob->context_saver = cs;
mob->output_stream = cs->stream;
+ cs->context_size = mob->context_size;
+ cs->data = apr_pcalloc(mob->pool, sizeof(*cs->data) * cs->context_size);
+ cs->len = apr_pcalloc(mob->pool, sizeof(*cs->len) * cs->context_size);
}
-/* A stream which prints SVN_DIFF__UNIFIED_CONTEXT_SIZE lines to
+/* A stream which prints LINES_TO_PRINT (based on context_size) lines to
BATON->REAL_OUTPUT_STREAM, and then changes BATON->OUTPUT_STREAM to
a context_saver; used for *trailing* context. */
@@ -815,7 +812,7 @@ make_trailing_context_printer(merge_output_baton_t *btn)
svn_pool_clear(btn->pool);
tcp = apr_pcalloc(btn->pool, sizeof(*tcp));
- tcp->lines_to_print = SVN_DIFF__UNIFIED_CONTEXT_SIZE;
+ tcp->lines_to_print = btn->context_size;
tcp->mob = btn;
s = svn_stream_empty(btn->pool);
svn_stream_set_baton(s, tcp);
@@ -913,7 +910,8 @@ output_conflict(void *baton,
if (style == svn_diff_conflict_display_resolved_modified_latest)
{
if (diff)
- return svn_diff_output(diff, baton, &merge_output_vtable);
+ return svn_diff_output2(diff, baton, &merge_output_vtable,
+ btn->cancel_func, btn->cancel_baton);
else
style = svn_diff_conflict_display_modified_latest;
}
@@ -949,6 +947,25 @@ output_conflict(void *baton,
return SVN_NO_ERROR;
}
+static svn_error_t *
+output_conflict_with_context_marker(merge_output_baton_t *btn,
+ const char *label,
+ apr_off_t start,
+ apr_off_t length)
+{
+ if (length == 1)
+ SVN_ERR(svn_stream_printf(btn->output_stream, btn->pool,
+ "%s (%" APR_OFF_T_FMT ")",
+ label, start + 1));
+ else
+ SVN_ERR(svn_stream_printf(btn->output_stream, btn->pool,
+ "%s (%" APR_OFF_T_FMT ",%" APR_OFF_T_FMT ")",
+ label, start + 1, length));
+
+ SVN_ERR(output_marker_eol(btn));
+
+ return SVN_NO_ERROR;
+}
static svn_error_t *
output_conflict_with_context(void *baton,
@@ -966,7 +983,7 @@ output_conflict_with_context(void *baton,
trailing context)? If so, flush it. */
if (btn->output_stream == btn->context_saver->stream)
{
- if (btn->context_saver->total_written > SVN_DIFF__UNIFIED_CONTEXT_SIZE)
+ if (btn->context_saver->total_written > btn->context_size)
SVN_ERR(svn_stream_puts(btn->real_output_stream, "@@\n"));
SVN_ERR(flush_context_saver(btn->context_saver, btn->real_output_stream));
}
@@ -975,36 +992,24 @@ output_conflict_with_context(void *baton,
btn->output_stream = btn->real_output_stream;
/* Output the conflict itself. */
- SVN_ERR(svn_stream_printf(btn->output_stream, btn->pool,
- (modified_length == 1
- ? "%s (%" APR_OFF_T_FMT ")"
- : "%s (%" APR_OFF_T_FMT ",%" APR_OFF_T_FMT ")"),
- btn->markers[1],
- modified_start + 1, modified_length));
- SVN_ERR(output_marker_eol(btn));
+ SVN_ERR(output_conflict_with_context_marker(btn, btn->markers[1],
+ modified_start,
+ modified_length));
SVN_ERR(output_merge_token_range(NULL, btn, 1/*modified*/,
modified_start, modified_length));
- SVN_ERR(svn_stream_printf(btn->output_stream, btn->pool,
- (original_length == 1
- ? "%s (%" APR_OFF_T_FMT ")"
- : "%s (%" APR_OFF_T_FMT ",%" APR_OFF_T_FMT ")"),
- btn->markers[0],
- original_start + 1, original_length));
- SVN_ERR(output_marker_eol(btn));
+ SVN_ERR(output_conflict_with_context_marker(btn, btn->markers[0],
+ original_start,
+ original_length));
SVN_ERR(output_merge_token_range(NULL, btn, 0/*original*/,
original_start, original_length));
SVN_ERR(output_merge_marker(btn, 2/*separator*/));
SVN_ERR(output_merge_token_range(NULL, btn, 2/*latest*/,
latest_start, latest_length));
- SVN_ERR(svn_stream_printf(btn->output_stream, btn->pool,
- (latest_length == 1
- ? "%s (%" APR_OFF_T_FMT ")"
- : "%s (%" APR_OFF_T_FMT ",%" APR_OFF_T_FMT ")"),
- btn->markers[3],
- latest_start + 1, latest_length));
- SVN_ERR(output_marker_eol(btn));
+ SVN_ERR(output_conflict_with_context_marker(btn, btn->markers[3],
+ latest_start,
+ latest_length));
/* Go into print-trailing-context mode instead. */
make_trailing_context_printer(btn);
@@ -1049,7 +1054,7 @@ detect_eol(svn_string_t *token)
}
svn_error_t *
-svn_diff_mem_string_output_merge2(svn_stream_t *output_stream,
+svn_diff_mem_string_output_merge3(svn_stream_t *output_stream,
svn_diff_t *diff,
const svn_string_t *original,
const svn_string_t *modified,
@@ -1059,7 +1064,9 @@ svn_diff_mem_string_output_merge2(svn_stream_t *output_stream,
const char *conflict_latest,
const char *conflict_separator,
svn_diff_conflict_display_style_t style,
- apr_pool_t *pool)
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ apr_pool_t *scratch_pool)
{
merge_output_baton_t btn;
const char *eol;
@@ -1069,19 +1076,20 @@ svn_diff_mem_string_output_merge2(svn_stream_t *output_stream,
? &merge_only_conflicts_output_vtable : &merge_output_vtable;
memset(&btn, 0, sizeof(btn));
+ btn.context_size = SVN_DIFF__UNIFIED_CONTEXT_SIZE;
if (conflicts_only)
{
- btn.pool = svn_pool_create(pool);
+ btn.pool = svn_pool_create(scratch_pool);
make_context_saver(&btn);
btn.real_output_stream = output_stream;
}
else
btn.output_stream = output_stream;
- fill_source_tokens(&(btn.sources[0]), original, pool);
- fill_source_tokens(&(btn.sources[1]), modified, pool);
- fill_source_tokens(&(btn.sources[2]), latest, pool);
+ fill_source_tokens(&(btn.sources[0]), original, scratch_pool);
+ fill_source_tokens(&(btn.sources[1]), modified, scratch_pool);
+ fill_source_tokens(&(btn.sources[2]), latest, scratch_pool);
btn.conflict_style = style;
@@ -1095,67 +1103,33 @@ svn_diff_mem_string_output_merge2(svn_stream_t *output_stream,
eol = APR_EOL_STR; /* use the platform default */
btn.marker_eol = eol;
+ btn.cancel_func = cancel_func;
+ btn.cancel_baton = cancel_baton;
SVN_ERR(svn_utf_cstring_from_utf8(&btn.markers[1],
conflict_modified
? conflict_modified
: "<<<<<<< (modified)",
- pool));
+ scratch_pool));
SVN_ERR(svn_utf_cstring_from_utf8(&btn.markers[0],
conflict_original
? conflict_original
: "||||||| (original)",
- pool));
+ scratch_pool));
SVN_ERR(svn_utf_cstring_from_utf8(&btn.markers[2],
conflict_separator
? conflict_separator
: "=======",
- pool));
+ scratch_pool));
SVN_ERR(svn_utf_cstring_from_utf8(&btn.markers[3],
conflict_latest
? conflict_latest
: ">>>>>>> (latest)",
- pool));
+ scratch_pool));
- SVN_ERR(svn_diff_output(diff, &btn, vtable));
+ SVN_ERR(svn_diff_output2(diff, &btn, vtable, cancel_func, cancel_baton));
if (conflicts_only)
svn_pool_destroy(btn.pool);
return SVN_NO_ERROR;
}
-
-svn_error_t *
-svn_diff_mem_string_output_merge(svn_stream_t *output_stream,
- svn_diff_t *diff,
- const svn_string_t *original,
- const svn_string_t *modified,
- const svn_string_t *latest,
- const char *conflict_original,
- const char *conflict_modified,
- const char *conflict_latest,
- const char *conflict_separator,
- svn_boolean_t display_original_in_conflict,
- svn_boolean_t display_resolved_conflicts,
- apr_pool_t *pool)
-{
- svn_diff_conflict_display_style_t style =
- svn_diff_conflict_display_modified_latest;
-
- if (display_resolved_conflicts)
- style = svn_diff_conflict_display_resolved_modified_latest;
-
- if (display_original_in_conflict)
- style = svn_diff_conflict_display_modified_original_latest;
-
- return svn_diff_mem_string_output_merge2(output_stream,
- diff,
- original,
- modified,
- latest,
- conflict_original,
- conflict_modified,
- conflict_latest,
- conflict_separator,
- style,
- pool);
-}
diff --git a/subversion/libsvn_diff/lcs.c b/subversion/libsvn_diff/lcs.c
index 8087a92f5c01..b420187d4e6c 100644
--- a/subversion/libsvn_diff/lcs.c
+++ b/subversion/libsvn_diff/lcs.c
@@ -345,7 +345,7 @@ svn_diff__lcs(svn_diff__position_t *position_list1, /* pointer to tail (ring) */
{
svn_diff__snake(fp + k, token_counts, &lcs_freelist, pool);
}
- /* for k > 0, deletions are free */
+ /* for k > 0, deletions are free */
for (k = (d > 0 ? d : 0) + p; k >= 0; k--)
{
svn_diff__snake(fp + k, token_counts, &lcs_freelist, pool);
diff --git a/subversion/libsvn_diff/libsvn_diff.pc.in b/subversion/libsvn_diff/libsvn_diff.pc.in
new file mode 100644
index 000000000000..eed9d886a9ac
--- /dev/null
+++ b/subversion/libsvn_diff/libsvn_diff.pc.in
@@ -0,0 +1,12 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libsvn_diff
+Description: Subversion Diff Library
+Version: @PACKAGE_VERSION@
+Requires: apr-@SVN_APR_MAJOR_VERSION@
+Requires.private: libsvn_subr
+Libs: -L${libdir} -lsvn_diff @SVN_ZLIB_LIBS@
+Cflags: -I${includedir}
diff --git a/subversion/libsvn_diff/parse-diff.c b/subversion/libsvn_diff/parse-diff.c
index e269ef925b38..3f794b8b1fa7 100644
--- a/subversion/libsvn_diff/parse-diff.c
+++ b/subversion/libsvn_diff/parse-diff.c
@@ -35,9 +35,12 @@
#include "svn_utf.h"
#include "svn_dirent_uri.h"
#include "svn_diff.h"
+#include "svn_ctype.h"
+#include "svn_mergeinfo.h"
#include "private/svn_eol_private.h"
#include "private/svn_dep_compat.h"
+#include "private/svn_sorts_private.h"
/* Helper macro for readability */
#define starts_with(str, start) \
@@ -385,7 +388,6 @@ svn_diff_hunk_readline_diff_text(svn_diff_hunk_t *hunk,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
- svn_diff_hunk_t dummy;
svn_stringbuf_t *line;
apr_size_t max_len;
apr_off_t pos;
@@ -415,33 +417,10 @@ svn_diff_hunk_readline_diff_text(svn_diff_hunk_t *hunk,
if (hunk->patch->reverse)
{
- if (parse_hunk_header(line->data, &dummy, "@@", scratch_pool))
- {
- /* Line is a hunk header, reverse it. */
- line = svn_stringbuf_createf(result_pool,
- "@@ -%lu,%lu +%lu,%lu @@",
- hunk->modified_start,
- hunk->modified_length,
- hunk->original_start,
- hunk->original_length);
- }
- else if (parse_hunk_header(line->data, &dummy, "##", scratch_pool))
- {
- /* Line is a hunk header, reverse it. */
- line = svn_stringbuf_createf(result_pool,
- "## -%lu,%lu +%lu,%lu ##",
- hunk->modified_start,
- hunk->modified_length,
- hunk->original_start,
- hunk->original_length);
- }
- else
- {
- if (line->data[0] == '+')
- line->data[0] = '-';
- else if (line->data[0] == '-')
- line->data[0] = '+';
- }
+ if (line->data[0] == '+')
+ line->data[0] = '-';
+ else if (line->data[0] == '-')
+ line->data[0] = '+';
}
*stringbuf = line;
@@ -471,6 +450,147 @@ parse_prop_name(const char **prop_name, const char *header,
return SVN_NO_ERROR;
}
+
+/* A helper function to parse svn:mergeinfo diffs.
+ *
+ * These diffs use a special pretty-print format, for instance:
+ *
+ * Added: svn:mergeinfo
+ * ## -0,0 +0,1 ##
+ * Merged /trunk:r2-3
+ *
+ * The hunk header has the following format:
+ * ## -0,NUMBER_OF_REVERSE_MERGES +0,NUMBER_OF_FORWARD_MERGES ##
+ *
+ * At this point, the number of reverse merges has already been
+ * parsed into HUNK->ORIGINAL_LENGTH, and the number of forward
+ * merges has been parsed into HUNK->MODIFIED_LENGTH.
+ *
+ * The header is followed by a list of mergeinfo, one path per line.
+ * This function parses such lines. Lines describing reverse merges
+ * appear first, and then all lines describing forward merges appear.
+ *
+ * Parts of the line are affected by i18n. The words 'Merged'
+ * and 'Reverse-merged' can appear in any language and at any
+ * position within the line. We can only assume that a leading
+ * '/' starts the merge source path, the path is followed by
+ * ":r", which in turn is followed by a mergeinfo revision range,
+ * which is terminated by whitespace or end-of-string.
+ *
+ * If the current line meets the above criteria and we're able
+ * to parse valid mergeinfo from it, the resulting mergeinfo
+ * is added to patch->mergeinfo or patch->reverse_mergeinfo,
+ * and we proceed to the next line.
+ */
+static svn_error_t *
+parse_mergeinfo(svn_boolean_t *found_mergeinfo,
+ svn_stringbuf_t *line,
+ svn_diff_hunk_t *hunk,
+ svn_patch_t *patch,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ char *slash = strchr(line->data, '/');
+ char *colon = strrchr(line->data, ':');
+
+ *found_mergeinfo = FALSE;
+
+ if (slash && colon && colon[1] == 'r' && slash < colon)
+ {
+ svn_stringbuf_t *input;
+ svn_mergeinfo_t mergeinfo = NULL;
+ char *s;
+ svn_error_t *err;
+
+ input = svn_stringbuf_create_ensure(line->len, scratch_pool);
+
+ /* Copy the merge source path + colon */
+ s = slash;
+ while (s <= colon)
+ {
+ svn_stringbuf_appendbyte(input, *s);
+ s++;
+ }
+
+ /* skip 'r' after colon */
+ s++;
+
+ /* Copy the revision range. */
+ while (s < line->data + line->len)
+ {
+ if (svn_ctype_isspace(*s))
+ break;
+ svn_stringbuf_appendbyte(input, *s);
+ s++;
+ }
+
+ err = svn_mergeinfo_parse(&mergeinfo, input->data, result_pool);
+ if (err && err->apr_err == SVN_ERR_MERGEINFO_PARSE_ERROR)
+ {
+ svn_error_clear(err);
+ mergeinfo = NULL;
+ }
+ else
+ SVN_ERR(err);
+
+ if (mergeinfo)
+ {
+ if (hunk->original_length > 0) /* reverse merges */
+ {
+ if (patch->reverse)
+ {
+ if (patch->mergeinfo == NULL)
+ patch->mergeinfo = mergeinfo;
+ else
+ SVN_ERR(svn_mergeinfo_merge2(patch->mergeinfo,
+ mergeinfo,
+ result_pool,
+ scratch_pool));
+ }
+ else
+ {
+ if (patch->reverse_mergeinfo == NULL)
+ patch->reverse_mergeinfo = mergeinfo;
+ else
+ SVN_ERR(svn_mergeinfo_merge2(patch->reverse_mergeinfo,
+ mergeinfo,
+ result_pool,
+ scratch_pool));
+ }
+ hunk->original_length--;
+ }
+ else if (hunk->modified_length > 0) /* forward merges */
+ {
+ if (patch->reverse)
+ {
+ if (patch->reverse_mergeinfo == NULL)
+ patch->reverse_mergeinfo = mergeinfo;
+ else
+ SVN_ERR(svn_mergeinfo_merge2(patch->reverse_mergeinfo,
+ mergeinfo,
+ result_pool,
+ scratch_pool));
+ }
+ else
+ {
+ if (patch->mergeinfo == NULL)
+ patch->mergeinfo = mergeinfo;
+ else
+ SVN_ERR(svn_mergeinfo_merge2(patch->mergeinfo,
+ mergeinfo,
+ result_pool,
+ scratch_pool));
+ }
+ hunk->modified_length--;
+ }
+
+ *found_mergeinfo = TRUE;
+ }
+ }
+
+ return SVN_NO_ERROR;
+}
+
/* Return the next *HUNK from a PATCH in APR_FILE.
* If no hunk can be found, set *HUNK to NULL.
* Set IS_PROPERTY to TRUE if we have a property hunk. If the returned HUNK
@@ -600,6 +720,17 @@ parse_next_hunk(svn_diff_hunk_t **hunk,
continue;
}
+ if (in_hunk && *is_property && *prop_name &&
+ strcmp(*prop_name, SVN_PROP_MERGEINFO) == 0)
+ {
+ svn_boolean_t found_mergeinfo;
+
+ SVN_ERR(parse_mergeinfo(&found_mergeinfo, line, *hunk, patch,
+ result_pool, iterpool));
+ if (found_mergeinfo)
+ continue; /* Proceed to the next line in the patch. */
+ }
+
if (in_hunk)
{
char c;
@@ -1192,6 +1323,13 @@ parse_hunks(svn_patch_t *patch, apr_file_t *apr_file,
prop_name = last_prop_name;
else
last_prop_name = prop_name;
+
+ /* Skip svn:mergeinfo properties.
+ * Mergeinfo data cannot be represented as a hunk and
+ * is therefore stored in PATCH itself. */
+ if (strcmp(prop_name, SVN_PROP_MERGEINFO) == 0)
+ continue;
+
SVN_ERR(add_property_hunk(patch, prop_name, hunk, prop_operation,
result_pool));
}
@@ -1229,7 +1367,7 @@ static struct transition transitions[] =
};
svn_error_t *
-svn_diff_parse_next_patch(svn_patch_t **patch,
+svn_diff_parse_next_patch(svn_patch_t **patch_p,
svn_patch_file_t *patch_file,
svn_boolean_t reverse,
svn_boolean_t ignore_whitespace,
@@ -1240,16 +1378,17 @@ svn_diff_parse_next_patch(svn_patch_t **patch,
svn_boolean_t eof;
svn_boolean_t line_after_tree_header_read = FALSE;
apr_pool_t *iterpool;
+ svn_patch_t *patch;
enum parse_state state = state_start;
if (apr_file_eof(patch_file->apr_file) == APR_EOF)
{
/* No more patches here. */
- *patch = NULL;
+ *patch_p = NULL;
return SVN_NO_ERROR;
}
- *patch = apr_pcalloc(result_pool, sizeof(**patch));
+ patch = apr_pcalloc(result_pool, sizeof(*patch));
pos = patch_file->next_patch_offset;
SVN_ERR(svn_io_file_seek(patch_file->apr_file, APR_SET, &pos, scratch_pool));
@@ -1282,7 +1421,7 @@ svn_diff_parse_next_patch(svn_patch_t **patch,
if (starts_with(line->data, transitions[i].expected_input)
&& state == transitions[i].required_state)
{
- SVN_ERR(transitions[i].fn(&state, line->data, *patch,
+ SVN_ERR(transitions[i].fn(&state, line->data, patch,
result_pool, iterpool));
valid_header_line = TRUE;
break;
@@ -1328,22 +1467,22 @@ svn_diff_parse_next_patch(svn_patch_t **patch,
}
while (! eof);
- (*patch)->reverse = reverse;
+ patch->reverse = reverse;
if (reverse)
{
const char *temp;
- temp = (*patch)->old_filename;
- (*patch)->old_filename = (*patch)->new_filename;
- (*patch)->new_filename = temp;
+ temp = patch->old_filename;
+ patch->old_filename = patch->new_filename;
+ patch->new_filename = temp;
}
- if ((*patch)->old_filename == NULL || (*patch)->new_filename == NULL)
+ if (patch->old_filename == NULL || patch->new_filename == NULL)
{
/* Something went wrong, just discard the result. */
- *patch = NULL;
+ patch = NULL;
}
else
- SVN_ERR(parse_hunks(*patch, patch_file->apr_file, ignore_whitespace,
+ SVN_ERR(parse_hunks(patch, patch_file->apr_file, ignore_whitespace,
result_pool, iterpool));
svn_pool_destroy(iterpool);
@@ -1352,16 +1491,16 @@ svn_diff_parse_next_patch(svn_patch_t **patch,
SVN_ERR(svn_io_file_seek(patch_file->apr_file, APR_CUR,
&patch_file->next_patch_offset, scratch_pool));
- if (*patch)
+ if (patch)
{
/* Usually, hunks appear in the patch sorted by their original line
* offset. But just in case they weren't parsed in this order for
* some reason, we sort them so that our caller can assume that hunks
* are sorted as if parsed from a usual patch. */
- qsort((*patch)->hunks->elts, (*patch)->hunks->nelts,
- (*patch)->hunks->elt_size, compare_hunks);
+ svn_sort__array(patch->hunks, compare_hunks);
}
+ *patch_p = patch;
return SVN_NO_ERROR;
}
diff --git a/subversion/libsvn_diff/util.c b/subversion/libsvn_diff/util.c
index 412b20be1f95..a931822ca258 100644
--- a/subversion/libsvn_diff/util.c
+++ b/subversion/libsvn_diff/util.c
@@ -34,11 +34,11 @@
#include "svn_diff.h"
#include "svn_types.h"
#include "svn_ctype.h"
-#include "svn_sorts.h"
#include "svn_utf.h"
#include "svn_version.h"
#include "private/svn_diff_private.h"
+#include "private/svn_sorts_private.h"
#include "diff.h"
#include "svn_private_config.h"
@@ -77,9 +77,11 @@ svn_diff_contains_diffs(svn_diff_t *diff)
}
svn_error_t *
-svn_diff_output(svn_diff_t *diff,
- void *output_baton,
- const svn_diff_output_fns_t *vtable)
+svn_diff_output2(svn_diff_t *diff,
+ void *output_baton,
+ const svn_diff_output_fns_t *vtable,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton)
{
svn_error_t *(*output_fn)(void *,
apr_off_t, apr_off_t,
@@ -88,6 +90,9 @@ svn_diff_output(svn_diff_t *diff,
while (diff != NULL)
{
+ if (cancel_func)
+ SVN_ERR(cancel_func(cancel_baton));
+
switch (diff->type)
{
case svn_diff__type_common:
@@ -449,11 +454,19 @@ display_mergeinfo_diff(const char *old_mergeinfo_val,
new_mergeinfo_hash,
TRUE, pool, pool));
+ /* Print a hint for 'svn patch' or smilar tools, indicating the
+ * number of reverse-merges and forward-merges. */
+ SVN_ERR(svn_stream_printf_from_utf8(outstream, encoding, pool,
+ "## -0,%u +0,%u ##%s",
+ apr_hash_count(deleted),
+ apr_hash_count(added),
+ APR_EOL_STR));
+
for (hi = apr_hash_first(pool, deleted);
hi; hi = apr_hash_next(hi))
{
- const char *from_path = svn__apr_hash_index_key(hi);
- svn_rangelist_t *merge_revarray = svn__apr_hash_index_val(hi);
+ const char *from_path = apr_hash_this_key(hi);
+ svn_rangelist_t *merge_revarray = apr_hash_this_val(hi);
svn_string_t *merge_revstr;
svn_pool_clear(iterpool);
@@ -469,8 +482,8 @@ display_mergeinfo_diff(const char *old_mergeinfo_val,
for (hi = apr_hash_first(pool, added);
hi; hi = apr_hash_next(hi))
{
- const char *from_path = svn__apr_hash_index_key(hi);
- svn_rangelist_t *merge_revarray = svn__apr_hash_index_val(hi);
+ const char *from_path = apr_hash_this_key(hi);
+ svn_rangelist_t *merge_revarray = apr_hash_this_val(hi);
svn_string_t *merge_revstr;
svn_pool_clear(iterpool);
@@ -487,7 +500,7 @@ display_mergeinfo_diff(const char *old_mergeinfo_val,
return SVN_NO_ERROR;
}
-/* qsort callback handling svn_prop_t by name */
+/* svn_sort__array callback handling svn_prop_t by name */
static int
propchange_sort(const void *k1, const void *k2)
{
@@ -503,6 +516,9 @@ svn_diff__display_prop_diffs(svn_stream_t *outstream,
const apr_array_header_t *propchanges,
apr_hash_t *original_props,
svn_boolean_t pretty_print_mergeinfo,
+ int context_size,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
apr_pool_t *scratch_pool)
{
apr_pool_t *pool = scratch_pool;
@@ -510,7 +526,7 @@ svn_diff__display_prop_diffs(svn_stream_t *outstream,
apr_array_header_t *changes = apr_array_copy(scratch_pool, propchanges);
int i;
- qsort(changes->elts, changes->nelts, changes->elt_size, propchange_sort);
+ svn_sort__array(changes, propchange_sort);
for (i = 0; i < changes->nelts; i++)
{
@@ -586,10 +602,11 @@ svn_diff__display_prop_diffs(svn_stream_t *outstream,
* from the diff header. But there usually are no files which
* UNIX patch could apply the property diff to, so we use "##"
* instead of "@@" as the default hunk delimiter for property diffs.
- * We also supress the diff header. */
- SVN_ERR(svn_diff_mem_string_output_unified2(
+ * We also suppress the diff header. */
+ SVN_ERR(svn_diff_mem_string_output_unified3(
outstream, diff, FALSE /* no header */, "##", NULL, NULL,
- encoding, orig, val, iterpool));
+ encoding, orig, val, context_size,
+ cancel_func, cancel_baton, iterpool));
}
}
svn_pool_destroy(iterpool);