diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-08-05 16:22:51 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-08-05 16:22:51 +0000 |
commit | cf46733632c7279a9fd0fe6ce26f9185a4ae82a9 (patch) | |
tree | da27775a2161723ef342e91af41a8b51fedef405 /subversion/libsvn_diff | |
parent | bb0ef45f7c46b0ae221b26265ef98a768c33f820 (diff) | |
download | subversion-tarball-master.tar.gz |
subversion-1.9.7HEADsubversion-1.9.7master
Diffstat (limited to 'subversion/libsvn_diff')
-rw-r--r-- | subversion/libsvn_diff/binary_diff.c | 221 | ||||
-rw-r--r-- | subversion/libsvn_diff/deprecated.c | 175 | ||||
-rw-r--r-- | subversion/libsvn_diff/diff4.c | 2 | ||||
-rw-r--r-- | subversion/libsvn_diff/diff_file.c | 198 | ||||
-rw-r--r-- | subversion/libsvn_diff/diff_memory.c | 204 | ||||
-rw-r--r-- | subversion/libsvn_diff/lcs.c | 2 | ||||
-rw-r--r-- | subversion/libsvn_diff/libsvn_diff.pc.in | 12 | ||||
-rw-r--r-- | subversion/libsvn_diff/parse-diff.c | 223 | ||||
-rw-r--r-- | subversion/libsvn_diff/util.c | 43 |
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 0000000..035794d --- /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 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_clear(subpool); + SVN_ERR(svn_stream_puts(output_stream, 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_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 891ad5f..b8dc097 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 9f3cb8c..1ecbb38 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 830552a..f54522e 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 00f4c7f..d9d800d 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 8087a92..b420187 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 0000000..eed9d88 --- /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 e269ef9..3f794b8 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 412b20b..a931822 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); |