diff options
author | Lorry Tar Creator <lorry-tar-importer@baserock.org> | 2015-03-18 13:33:26 +0000 |
---|---|---|
committer | <> | 2015-07-08 14:41:01 +0000 |
commit | bb0ef45f7c46b0ae221b26265ef98a768c33f820 (patch) | |
tree | 98bae10dde41c746c51ae97ec4f879e330415aa7 /subversion/libsvn_diff/diff_tree.c | |
parent | 239dfafe71711b2f4c43d7b90a1228d7bdc5195e (diff) | |
download | subversion-tarball-bb0ef45f7c46b0ae221b26265ef98a768c33f820.tar.gz |
Imported from /home/lorry/working-area/delta_subversion-tarball/subversion-1.8.13.tar.gz.subversion-1.8.13
Diffstat (limited to 'subversion/libsvn_diff/diff_tree.c')
-rw-r--r-- | subversion/libsvn_diff/diff_tree.c | 1705 |
1 files changed, 1705 insertions, 0 deletions
diff --git a/subversion/libsvn_diff/diff_tree.c b/subversion/libsvn_diff/diff_tree.c new file mode 100644 index 0000000..8490179 --- /dev/null +++ b/subversion/libsvn_diff/diff_tree.c @@ -0,0 +1,1705 @@ +/* + * diff_tree.c : default diff tree processor + * + * ==================================================================== + * 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 <apr_pools.h> +#include <apr_general.h> + +#include <assert.h> + +#include "svn_dirent_uri.h" +#include "svn_error.h" +#include "svn_io.h" +#include "svn_pools.h" +#include "svn_props.h" +#include "svn_types.h" + +#include "private/svn_diff_tree.h" +#include "svn_private_config.h" + +typedef struct tree_processor_t +{ + svn_diff_tree_processor_t tp; + + /* void *future_extension */ +} tree_processor_t; + + +static svn_error_t * +default_dir_opened(void **new_dir_baton, + svn_boolean_t *skip, + svn_boolean_t *skip_children, + const char *relpath, + const svn_diff_source_t *left_source, + const svn_diff_source_t *right_source, + const svn_diff_source_t *copyfrom_source, + void *parent_dir_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + *new_dir_baton = NULL; + return SVN_NO_ERROR; +} + +static svn_error_t * +default_dir_added(const char *relpath, + const svn_diff_source_t *copyfrom_source, + const svn_diff_source_t *right_source, + /*const*/ apr_hash_t *copyfrom_props, + /*const*/ apr_hash_t *right_props, + void *dir_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + SVN_ERR(processor->dir_closed(relpath, NULL, right_source, + dir_baton, processor, + scratch_pool)); + + return SVN_NO_ERROR; +} + +static svn_error_t * +default_dir_deleted(const char *relpath, + const svn_diff_source_t *left_source, + /*const*/ apr_hash_t *left_props, + void *dir_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + SVN_ERR(processor->dir_closed(relpath, left_source, NULL, + dir_baton, processor, + scratch_pool)); + return SVN_NO_ERROR; +} + +static svn_error_t * +default_dir_changed(const char *relpath, + const svn_diff_source_t *left_source, + const svn_diff_source_t *right_source, + /*const*/ apr_hash_t *left_props, + /*const*/ apr_hash_t *right_props, + const apr_array_header_t *prop_changes, + void *dir_baton, + const struct svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + SVN_ERR(processor->dir_closed(relpath, + left_source, right_source, + dir_baton, + processor, scratch_pool)); + return SVN_NO_ERROR; +} + +static svn_error_t * +default_dir_closed(const char *relpath, + const svn_diff_source_t *left_source, + const svn_diff_source_t *right_source, + void *dir_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + return SVN_NO_ERROR; +} + +static svn_error_t * +default_file_opened(void **new_file_baton, + svn_boolean_t *skip, + const char *relpath, + const svn_diff_source_t *left_source, + const svn_diff_source_t *right_source, + const svn_diff_source_t *copyfrom_source, + void *dir_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + *new_file_baton = dir_baton; + return SVN_NO_ERROR; +} + +static svn_error_t * +default_file_added(const char *relpath, + const svn_diff_source_t *copyfrom_source, + const svn_diff_source_t *right_source, + const char *copyfrom_file, + const char *right_file, + /*const*/ apr_hash_t *copyfrom_props, + /*const*/ apr_hash_t *right_props, + void *file_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + SVN_ERR(processor->file_closed(relpath, + NULL, right_source, + file_baton, processor, scratch_pool)); + return SVN_NO_ERROR; +} + +static svn_error_t * +default_file_deleted(const char *relpath, + const svn_diff_source_t *left_source, + const char *left_file, + /*const*/ apr_hash_t *left_props, + void *file_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + SVN_ERR(processor->file_closed(relpath, + left_source, NULL, + file_baton, processor, scratch_pool)); + return SVN_NO_ERROR; +} + +static svn_error_t * +default_file_changed(const char *relpath, + const svn_diff_source_t *left_source, + const svn_diff_source_t *right_source, + const char *left_file, + const char *right_file, + /*const*/ apr_hash_t *left_props, + /*const*/ apr_hash_t *right_props, + svn_boolean_t file_modified, + const apr_array_header_t *prop_changes, + void *file_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + SVN_ERR(processor->file_closed(relpath, + left_source, right_source, + file_baton, processor, scratch_pool)); + return SVN_NO_ERROR; +} + +static svn_error_t * +default_file_closed(const char *relpath, + const svn_diff_source_t *left_source, + const svn_diff_source_t *right_source, + void *file_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + return SVN_NO_ERROR; +} + +static svn_error_t * +default_node_absent(const char *relpath, + void *dir_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + return SVN_NO_ERROR; +} + +svn_diff_tree_processor_t * +svn_diff__tree_processor_create(void *baton, + apr_pool_t *result_pool) +{ + tree_processor_t *wrapper; + wrapper = apr_pcalloc(result_pool, sizeof(*wrapper)); + + wrapper->tp.baton = baton; + + wrapper->tp.dir_opened = default_dir_opened; + wrapper->tp.dir_added = default_dir_added; + wrapper->tp.dir_deleted = default_dir_deleted; + wrapper->tp.dir_changed = default_dir_changed; + wrapper->tp.dir_closed = default_dir_closed; + + wrapper->tp.file_opened = default_file_opened; + wrapper->tp.file_added = default_file_added; + wrapper->tp.file_deleted = default_file_deleted; + wrapper->tp.file_changed = default_file_changed; + wrapper->tp.file_closed = default_file_closed; + + wrapper->tp.node_absent = default_node_absent; + + + return &wrapper->tp; +} + +struct reverse_tree_baton_t +{ + const svn_diff_tree_processor_t *processor; + const char *prefix_relpath; +}; + +static svn_error_t * +reverse_dir_opened(void **new_dir_baton, + svn_boolean_t *skip, + svn_boolean_t *skip_children, + const char *relpath, + const svn_diff_source_t *left_source, + const svn_diff_source_t *right_source, + const svn_diff_source_t *copyfrom_source, + void *parent_dir_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + struct reverse_tree_baton_t *rb = processor->baton; + + if (rb->prefix_relpath) + relpath = svn_relpath_join(rb->prefix_relpath, relpath, scratch_pool); + + SVN_ERR(rb->processor->dir_opened(new_dir_baton, skip, skip_children, + relpath, + right_source, left_source, + NULL /* copyfrom */, + parent_dir_baton, + rb->processor, + result_pool, scratch_pool)); + return SVN_NO_ERROR; +} + +static svn_error_t * +reverse_dir_added(const char *relpath, + const svn_diff_source_t *copyfrom_source, + const svn_diff_source_t *right_source, + /*const*/ apr_hash_t *copyfrom_props, + /*const*/ apr_hash_t *right_props, + void *dir_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + struct reverse_tree_baton_t *rb = processor->baton; + + if (rb->prefix_relpath) + relpath = svn_relpath_join(rb->prefix_relpath, relpath, scratch_pool); + + SVN_ERR(rb->processor->dir_deleted(relpath, + right_source, + right_props, + dir_baton, + rb->processor, + scratch_pool)); + + return SVN_NO_ERROR; +} + +static svn_error_t * +reverse_dir_deleted(const char *relpath, + const svn_diff_source_t *left_source, + /*const*/ apr_hash_t *left_props, + void *dir_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + struct reverse_tree_baton_t *rb = processor->baton; + + if (rb->prefix_relpath) + relpath = svn_relpath_join(rb->prefix_relpath, relpath, scratch_pool); + + SVN_ERR(rb->processor->dir_added(relpath, + NULL, + left_source, + NULL, + left_props, + dir_baton, + rb->processor, + scratch_pool)); + return SVN_NO_ERROR; +} + +static svn_error_t * +reverse_dir_changed(const char *relpath, + const svn_diff_source_t *left_source, + const svn_diff_source_t *right_source, + /*const*/ apr_hash_t *left_props, + /*const*/ apr_hash_t *right_props, + const apr_array_header_t *prop_changes, + void *dir_baton, + const struct svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + struct reverse_tree_baton_t *rb = processor->baton; + apr_array_header_t *reversed_prop_changes = NULL; + + if (rb->prefix_relpath) + relpath = svn_relpath_join(rb->prefix_relpath, relpath, scratch_pool); + + if (prop_changes) + { + SVN_ERR_ASSERT(left_props != NULL && right_props != NULL); + SVN_ERR(svn_prop_diffs(&reversed_prop_changes, left_props, right_props, + scratch_pool)); + } + + SVN_ERR(rb->processor->dir_changed(relpath, + right_source, + left_source, + right_props, + left_props, + reversed_prop_changes, + dir_baton, + rb->processor, + scratch_pool)); + return SVN_NO_ERROR; +} + +static svn_error_t * +reverse_dir_closed(const char *relpath, + const svn_diff_source_t *left_source, + const svn_diff_source_t *right_source, + void *dir_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + struct reverse_tree_baton_t *rb = processor->baton; + + if (rb->prefix_relpath) + relpath = svn_relpath_join(rb->prefix_relpath, relpath, scratch_pool); + + SVN_ERR(rb->processor->dir_closed(relpath, + right_source, + left_source, + dir_baton, + rb->processor, + scratch_pool)); + return SVN_NO_ERROR; +} + +static svn_error_t * +reverse_file_opened(void **new_file_baton, + svn_boolean_t *skip, + const char *relpath, + const svn_diff_source_t *left_source, + const svn_diff_source_t *right_source, + const svn_diff_source_t *copyfrom_source, + void *dir_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + struct reverse_tree_baton_t *rb = processor->baton; + + if (rb->prefix_relpath) + relpath = svn_relpath_join(rb->prefix_relpath, relpath, scratch_pool); + + SVN_ERR(rb->processor->file_opened(new_file_baton, + skip, + relpath, + right_source, + left_source, + NULL /* copy_from */, + dir_baton, + rb->processor, + result_pool, + scratch_pool)); + return SVN_NO_ERROR; +} + +static svn_error_t * +reverse_file_added(const char *relpath, + const svn_diff_source_t *copyfrom_source, + const svn_diff_source_t *right_source, + const char *copyfrom_file, + const char *right_file, + /*const*/ apr_hash_t *copyfrom_props, + /*const*/ apr_hash_t *right_props, + void *file_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + struct reverse_tree_baton_t *rb = processor->baton; + + if (rb->prefix_relpath) + relpath = svn_relpath_join(rb->prefix_relpath, relpath, scratch_pool); + + SVN_ERR(rb->processor->file_deleted(relpath, + right_source, + right_file, + right_props, + file_baton, + rb->processor, + scratch_pool)); + return SVN_NO_ERROR; +} + +static svn_error_t * +reverse_file_deleted(const char *relpath, + const svn_diff_source_t *left_source, + const char *left_file, + /*const*/ apr_hash_t *left_props, + void *file_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + struct reverse_tree_baton_t *rb = processor->baton; + + if (rb->prefix_relpath) + relpath = svn_relpath_join(rb->prefix_relpath, relpath, scratch_pool); + + SVN_ERR(rb->processor->file_added(relpath, + NULL /* copyfrom src */, + left_source, + NULL /* copyfrom file */, + left_file, + NULL /* copyfrom props */, + left_props, + file_baton, + rb->processor, + scratch_pool)); + return SVN_NO_ERROR; +} + +static svn_error_t * +reverse_file_changed(const char *relpath, + const svn_diff_source_t *left_source, + const svn_diff_source_t *right_source, + const char *left_file, + const char *right_file, + /*const*/ apr_hash_t *left_props, + /*const*/ apr_hash_t *right_props, + svn_boolean_t file_modified, + const apr_array_header_t *prop_changes, + void *file_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + struct reverse_tree_baton_t *rb = processor->baton; + apr_array_header_t *reversed_prop_changes = NULL; + + if (rb->prefix_relpath) + relpath = svn_relpath_join(rb->prefix_relpath, relpath, scratch_pool); + + if (prop_changes) + { + SVN_ERR_ASSERT(left_props != NULL && right_props != NULL); + SVN_ERR(svn_prop_diffs(&reversed_prop_changes, left_props, right_props, + scratch_pool)); + } + + SVN_ERR(rb->processor->file_changed(relpath, + right_source, + left_source, + right_file, + left_file, + right_props, + left_props, + file_modified, + reversed_prop_changes, + file_baton, + rb->processor, + scratch_pool)); + return SVN_NO_ERROR; +} + +static svn_error_t * +reverse_file_closed(const char *relpath, + const svn_diff_source_t *left_source, + const svn_diff_source_t *right_source, + void *file_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + struct reverse_tree_baton_t *rb = processor->baton; + + if (rb->prefix_relpath) + relpath = svn_relpath_join(rb->prefix_relpath, relpath, scratch_pool); + + SVN_ERR(rb->processor->file_closed(relpath, + right_source, + left_source, + file_baton, + rb->processor, + scratch_pool)); + + return SVN_NO_ERROR; +} + +static svn_error_t * +reverse_node_absent(const char *relpath, + void *dir_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + struct reverse_tree_baton_t *rb = processor->baton; + + if (rb->prefix_relpath) + relpath = svn_relpath_join(rb->prefix_relpath, relpath, scratch_pool); + + SVN_ERR(rb->processor->node_absent(relpath, + dir_baton, + rb->processor, + scratch_pool)); + return SVN_NO_ERROR; +} + + +const svn_diff_tree_processor_t * +svn_diff__tree_processor_reverse_create(const svn_diff_tree_processor_t * processor, + const char *prefix_relpath, + apr_pool_t *result_pool) +{ + struct reverse_tree_baton_t *rb; + svn_diff_tree_processor_t *reverse; + + rb = apr_pcalloc(result_pool, sizeof(*rb)); + rb->processor = processor; + if (prefix_relpath) + rb->prefix_relpath = apr_pstrdup(result_pool, prefix_relpath); + + reverse = svn_diff__tree_processor_create(rb, result_pool); + + reverse->dir_opened = reverse_dir_opened; + reverse->dir_added = reverse_dir_added; + reverse->dir_deleted = reverse_dir_deleted; + reverse->dir_changed = reverse_dir_changed; + reverse->dir_closed = reverse_dir_closed; + + reverse->file_opened = reverse_file_opened; + reverse->file_added = reverse_file_added; + reverse->file_deleted = reverse_file_deleted; + reverse->file_changed = reverse_file_changed; + reverse->file_closed = reverse_file_closed; + + reverse->node_absent = reverse_node_absent; + + return reverse; +} + +struct filter_tree_baton_t +{ + const svn_diff_tree_processor_t *processor; + const char *prefix_relpath; +}; + +static svn_error_t * +filter_dir_opened(void **new_dir_baton, + svn_boolean_t *skip, + svn_boolean_t *skip_children, + const char *relpath, + const svn_diff_source_t *left_source, + const svn_diff_source_t *right_source, + const svn_diff_source_t *copyfrom_source, + void *parent_dir_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + struct filter_tree_baton_t *fb = processor->baton; + + relpath = svn_relpath_skip_ancestor(fb->prefix_relpath, relpath); + + if (! relpath) + { + /* Skip work for this, but NOT for DESCENDANTS */ + *skip = TRUE; + return SVN_NO_ERROR; + } + + SVN_ERR(fb->processor->dir_opened(new_dir_baton, skip, skip_children, + relpath, + left_source, right_source, + copyfrom_source, + parent_dir_baton, + fb->processor, + result_pool, scratch_pool)); + return SVN_NO_ERROR; +} + +static svn_error_t * +filter_dir_added(const char *relpath, + const svn_diff_source_t *copyfrom_source, + const svn_diff_source_t *right_source, + /*const*/ apr_hash_t *copyfrom_props, + /*const*/ apr_hash_t *right_props, + void *dir_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + struct filter_tree_baton_t *fb = processor->baton; + + relpath = svn_relpath_skip_ancestor(fb->prefix_relpath, relpath); + assert(relpath != NULL); /* Driver error */ + + SVN_ERR(fb->processor->dir_added(relpath, + copyfrom_source, + right_source, + copyfrom_props, + right_props, + dir_baton, + fb->processor, + scratch_pool)); + + return SVN_NO_ERROR; +} + +static svn_error_t * +filter_dir_deleted(const char *relpath, + const svn_diff_source_t *left_source, + /*const*/ apr_hash_t *left_props, + void *dir_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + struct filter_tree_baton_t *fb = processor->baton; + + relpath = svn_relpath_skip_ancestor(fb->prefix_relpath, relpath); + assert(relpath != NULL); /* Driver error */ + + SVN_ERR(fb->processor->dir_deleted(relpath, + left_source, + left_props, + dir_baton, + fb->processor, + scratch_pool)); + + return SVN_NO_ERROR; +} + +static svn_error_t * +filter_dir_changed(const char *relpath, + const svn_diff_source_t *left_source, + const svn_diff_source_t *right_source, + /*const*/ apr_hash_t *left_props, + /*const*/ apr_hash_t *right_props, + const apr_array_header_t *prop_changes, + void *dir_baton, + const struct svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + struct filter_tree_baton_t *fb = processor->baton; + + relpath = svn_relpath_skip_ancestor(fb->prefix_relpath, relpath); + assert(relpath != NULL); /* Driver error */ + + SVN_ERR(fb->processor->dir_changed(relpath, + left_source, + right_source, + left_props, + right_props, + prop_changes, + dir_baton, + fb->processor, + scratch_pool)); + return SVN_NO_ERROR; +} + +static svn_error_t * +filter_dir_closed(const char *relpath, + const svn_diff_source_t *left_source, + const svn_diff_source_t *right_source, + void *dir_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + struct filter_tree_baton_t *fb = processor->baton; + + relpath = svn_relpath_skip_ancestor(fb->prefix_relpath, relpath); + assert(relpath != NULL); /* Driver error */ + + SVN_ERR(fb->processor->dir_closed(relpath, + left_source, + right_source, + dir_baton, + fb->processor, + scratch_pool)); + return SVN_NO_ERROR; +} + +static svn_error_t * +filter_file_opened(void **new_file_baton, + svn_boolean_t *skip, + const char *relpath, + const svn_diff_source_t *left_source, + const svn_diff_source_t *right_source, + const svn_diff_source_t *copyfrom_source, + void *dir_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + struct filter_tree_baton_t *fb = processor->baton; + + relpath = svn_relpath_skip_ancestor(fb->prefix_relpath, relpath); + + if (! relpath) + { + *skip = TRUE; + return SVN_NO_ERROR; + } + + SVN_ERR(fb->processor->file_opened(new_file_baton, + skip, + relpath, + left_source, + right_source, + copyfrom_source, + dir_baton, + fb->processor, + result_pool, + scratch_pool)); + return SVN_NO_ERROR; +} + +static svn_error_t * +filter_file_added(const char *relpath, + const svn_diff_source_t *copyfrom_source, + const svn_diff_source_t *right_source, + const char *copyfrom_file, + const char *right_file, + /*const*/ apr_hash_t *copyfrom_props, + /*const*/ apr_hash_t *right_props, + void *file_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + struct filter_tree_baton_t *fb = processor->baton; + + relpath = svn_relpath_skip_ancestor(fb->prefix_relpath, relpath); + assert(relpath != NULL); /* Driver error */ + + SVN_ERR(fb->processor->file_added(relpath, + copyfrom_source, + right_source, + copyfrom_file, + right_file, + copyfrom_props, + right_props, + file_baton, + fb->processor, + scratch_pool)); + return SVN_NO_ERROR; +} + +static svn_error_t * +filter_file_deleted(const char *relpath, + const svn_diff_source_t *left_source, + const char *left_file, + /*const*/ apr_hash_t *left_props, + void *file_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + struct filter_tree_baton_t *fb = processor->baton; + + relpath = svn_relpath_skip_ancestor(fb->prefix_relpath, relpath); + assert(relpath != NULL); /* Driver error */ + + SVN_ERR(fb->processor->file_deleted(relpath, + left_source, + left_file, + left_props, + file_baton, + fb->processor, + scratch_pool)); + + return SVN_NO_ERROR; +} + +static svn_error_t * +filter_file_changed(const char *relpath, + const svn_diff_source_t *left_source, + const svn_diff_source_t *right_source, + const char *left_file, + const char *right_file, + /*const*/ apr_hash_t *left_props, + /*const*/ apr_hash_t *right_props, + svn_boolean_t file_modified, + const apr_array_header_t *prop_changes, + void *file_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + struct filter_tree_baton_t *fb = processor->baton; + + relpath = svn_relpath_skip_ancestor(fb->prefix_relpath, relpath); + assert(relpath != NULL); /* Driver error */ + + SVN_ERR(fb->processor->file_changed(relpath, + left_source, + right_source, + left_file, + right_file, + left_props, + right_props, + file_modified, + prop_changes, + file_baton, + fb->processor, + scratch_pool)); + return SVN_NO_ERROR; +} + +static svn_error_t * +filter_file_closed(const char *relpath, + const svn_diff_source_t *left_source, + const svn_diff_source_t *right_source, + void *file_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + struct filter_tree_baton_t *fb = processor->baton; + + relpath = svn_relpath_skip_ancestor(fb->prefix_relpath, relpath); + assert(relpath != NULL); /* Driver error */ + + SVN_ERR(fb->processor->file_closed(relpath, + left_source, + right_source, + file_baton, + fb->processor, + scratch_pool)); + + return SVN_NO_ERROR; +} + +static svn_error_t * +filter_node_absent(const char *relpath, + void *dir_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + struct filter_tree_baton_t *fb = processor->baton; + + relpath = svn_relpath_skip_ancestor(fb->prefix_relpath, relpath); + assert(relpath != NULL); /* Driver error */ + + SVN_ERR(fb->processor->node_absent(relpath, + dir_baton, + fb->processor, + scratch_pool)); + return SVN_NO_ERROR; +} + + +const svn_diff_tree_processor_t * +svn_diff__tree_processor_filter_create(const svn_diff_tree_processor_t * processor, + const char *prefix_relpath, + apr_pool_t *result_pool) +{ + struct filter_tree_baton_t *fb; + svn_diff_tree_processor_t *filter; + + fb = apr_pcalloc(result_pool, sizeof(*fb)); + fb->processor = processor; + if (prefix_relpath) + fb->prefix_relpath = apr_pstrdup(result_pool, prefix_relpath); + + filter = svn_diff__tree_processor_create(fb, result_pool); + + filter->dir_opened = filter_dir_opened; + filter->dir_added = filter_dir_added; + filter->dir_deleted = filter_dir_deleted; + filter->dir_changed = filter_dir_changed; + filter->dir_closed = filter_dir_closed; + + filter->file_opened = filter_file_opened; + filter->file_added = filter_file_added; + filter->file_deleted = filter_file_deleted; + filter->file_changed = filter_file_changed; + filter->file_closed = filter_file_closed; + + filter->node_absent = filter_node_absent; + + return filter; +} + +struct copy_as_changed_baton_t +{ + const svn_diff_tree_processor_t *processor; +}; + +static svn_error_t * +copy_as_changed_dir_opened(void **new_dir_baton, + svn_boolean_t *skip, + svn_boolean_t *skip_children, + const char *relpath, + const svn_diff_source_t *left_source, + const svn_diff_source_t *right_source, + const svn_diff_source_t *copyfrom_source, + void *parent_dir_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + struct copy_as_changed_baton_t *cb = processor->baton; + + if (!left_source && copyfrom_source) + { + assert(right_source != NULL); + + left_source = copyfrom_source; + copyfrom_source = NULL; + } + + SVN_ERR(cb->processor->dir_opened(new_dir_baton, skip, skip_children, + relpath, + left_source, right_source, + copyfrom_source, + parent_dir_baton, + cb->processor, + result_pool, scratch_pool)); + return SVN_NO_ERROR; +} + +static svn_error_t * +copy_as_changed_dir_added(const char *relpath, + const svn_diff_source_t *copyfrom_source, + const svn_diff_source_t *right_source, + /*const*/ apr_hash_t *copyfrom_props, + /*const*/ apr_hash_t *right_props, + void *dir_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + struct copy_as_changed_baton_t *cb = processor->baton; + + if (copyfrom_source) + { + apr_array_header_t *propchanges; + SVN_ERR(svn_prop_diffs(&propchanges, right_props, copyfrom_props, + scratch_pool)); + SVN_ERR(cb->processor->dir_changed(relpath, + copyfrom_source, + right_source, + copyfrom_props, + right_props, + propchanges, + dir_baton, + cb->processor, + scratch_pool)); + } + else + { + SVN_ERR(cb->processor->dir_added(relpath, + copyfrom_source, + right_source, + copyfrom_props, + right_props, + dir_baton, + cb->processor, + scratch_pool)); + } + + return SVN_NO_ERROR; +} + +static svn_error_t * +copy_as_changed_dir_deleted(const char *relpath, + const svn_diff_source_t *left_source, + /*const*/ apr_hash_t *left_props, + void *dir_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + struct copy_as_changed_baton_t *cb = processor->baton; + + SVN_ERR(cb->processor->dir_deleted(relpath, + left_source, + left_props, + dir_baton, + cb->processor, + scratch_pool)); + + return SVN_NO_ERROR; +} + +static svn_error_t * +copy_as_changed_dir_changed(const char *relpath, + const svn_diff_source_t *left_source, + const svn_diff_source_t *right_source, + /*const*/ apr_hash_t *left_props, + /*const*/ apr_hash_t *right_props, + const apr_array_header_t *prop_changes, + void *dir_baton, + const struct svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + struct copy_as_changed_baton_t *cb = processor->baton; + + SVN_ERR(cb->processor->dir_changed(relpath, + left_source, + right_source, + left_props, + right_props, + prop_changes, + dir_baton, + cb->processor, + scratch_pool)); + return SVN_NO_ERROR; +} + +static svn_error_t * +copy_as_changed_dir_closed(const char *relpath, + const svn_diff_source_t *left_source, + const svn_diff_source_t *right_source, + void *dir_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + struct copy_as_changed_baton_t *cb = processor->baton; + + SVN_ERR(cb->processor->dir_closed(relpath, + left_source, + right_source, + dir_baton, + cb->processor, + scratch_pool)); + return SVN_NO_ERROR; +} + +static svn_error_t * +copy_as_changed_file_opened(void **new_file_baton, + svn_boolean_t *skip, + const char *relpath, + const svn_diff_source_t *left_source, + const svn_diff_source_t *right_source, + const svn_diff_source_t *copyfrom_source, + void *dir_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + struct copy_as_changed_baton_t *cb = processor->baton; + + if (!left_source && copyfrom_source) + { + assert(right_source != NULL); + + left_source = copyfrom_source; + copyfrom_source = NULL; + } + + SVN_ERR(cb->processor->file_opened(new_file_baton, + skip, + relpath, + left_source, + right_source, + copyfrom_source, + dir_baton, + cb->processor, + result_pool, + scratch_pool)); + return SVN_NO_ERROR; +} + +static svn_error_t * +copy_as_changed_file_added(const char *relpath, + const svn_diff_source_t *copyfrom_source, + const svn_diff_source_t *right_source, + const char *copyfrom_file, + const char *right_file, + /*const*/ apr_hash_t *copyfrom_props, + /*const*/ apr_hash_t *right_props, + void *file_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + struct copy_as_changed_baton_t *cb = processor->baton; + + if (copyfrom_source) + { + apr_array_header_t *propchanges; + svn_boolean_t same; + SVN_ERR(svn_prop_diffs(&propchanges, right_props, copyfrom_props, + scratch_pool)); + + /* "" is sometimes a marker for just modified (E.g. no-textdeltas), + and it is certainly not a file */ + if (*copyfrom_file && *right_file) + { + SVN_ERR(svn_io_files_contents_same_p(&same, copyfrom_file, + right_file, scratch_pool)); + } + else + same = FALSE; + + SVN_ERR(cb->processor->file_changed(relpath, + copyfrom_source, + right_source, + copyfrom_file, + right_file, + copyfrom_props, + right_props, + !same, + propchanges, + file_baton, + cb->processor, + scratch_pool)); + } + else + { + SVN_ERR(cb->processor->file_added(relpath, + copyfrom_source, + right_source, + copyfrom_file, + right_file, + copyfrom_props, + right_props, + file_baton, + cb->processor, + scratch_pool)); + } + return SVN_NO_ERROR; +} + +static svn_error_t * +copy_as_changed_file_deleted(const char *relpath, + const svn_diff_source_t *left_source, + const char *left_file, + /*const*/ apr_hash_t *left_props, + void *file_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + struct copy_as_changed_baton_t *cb = processor->baton; + + SVN_ERR(cb->processor->file_deleted(relpath, + left_source, + left_file, + left_props, + file_baton, + cb->processor, + scratch_pool)); + + return SVN_NO_ERROR; +} + +static svn_error_t * +copy_as_changed_file_changed(const char *relpath, + const svn_diff_source_t *left_source, + const svn_diff_source_t *right_source, + const char *left_file, + const char *right_file, + /*const*/ apr_hash_t *left_props, + /*const*/ apr_hash_t *right_props, + svn_boolean_t file_modified, + const apr_array_header_t *prop_changes, + void *file_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + struct copy_as_changed_baton_t *cb = processor->baton; + + SVN_ERR(cb->processor->file_changed(relpath, + left_source, + right_source, + left_file, + right_file, + left_props, + right_props, + file_modified, + prop_changes, + file_baton, + cb->processor, + scratch_pool)); + return SVN_NO_ERROR; +} + +static svn_error_t * +copy_as_changed_file_closed(const char *relpath, + const svn_diff_source_t *left_source, + const svn_diff_source_t *right_source, + void *file_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + struct copy_as_changed_baton_t *cb = processor->baton; + + SVN_ERR(cb->processor->file_closed(relpath, + left_source, + right_source, + file_baton, + cb->processor, + scratch_pool)); + + return SVN_NO_ERROR; +} + +static svn_error_t * +copy_as_changed_node_absent(const char *relpath, + void *dir_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + struct copy_as_changed_baton_t *cb = processor->baton; + + SVN_ERR(cb->processor->node_absent(relpath, + dir_baton, + cb->processor, + scratch_pool)); + return SVN_NO_ERROR; +} + + +const svn_diff_tree_processor_t * +svn_diff__tree_processor_copy_as_changed_create( + const svn_diff_tree_processor_t * processor, + apr_pool_t *result_pool) +{ + struct copy_as_changed_baton_t *cb; + svn_diff_tree_processor_t *filter; + + cb = apr_pcalloc(result_pool, sizeof(*cb)); + cb->processor = processor; + + filter = svn_diff__tree_processor_create(cb, result_pool); + filter->dir_opened = copy_as_changed_dir_opened; + filter->dir_added = copy_as_changed_dir_added; + filter->dir_deleted = copy_as_changed_dir_deleted; + filter->dir_changed = copy_as_changed_dir_changed; + filter->dir_closed = copy_as_changed_dir_closed; + + filter->file_opened = copy_as_changed_file_opened; + filter->file_added = copy_as_changed_file_added; + filter->file_deleted = copy_as_changed_file_deleted; + filter->file_changed = copy_as_changed_file_changed; + filter->file_closed = copy_as_changed_file_closed; + + filter->node_absent = copy_as_changed_node_absent; + + return filter; +} + + +/* Processor baton for the tee tree processor */ +struct tee_baton_t +{ + const svn_diff_tree_processor_t *p1; + const svn_diff_tree_processor_t *p2; +}; + +/* Wrapper baton for file and directory batons in the tee processor */ +struct tee_node_baton_t +{ + void *baton1; + void *baton2; +}; + +static svn_error_t * +tee_dir_opened(void **new_dir_baton, + svn_boolean_t *skip, + svn_boolean_t *skip_children, + const char *relpath, + const svn_diff_source_t *left_source, + const svn_diff_source_t *right_source, + const svn_diff_source_t *copyfrom_source, + void *parent_dir_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + struct tee_baton_t *tb = processor->baton; + struct tee_node_baton_t *pb = parent_dir_baton; + struct tee_node_baton_t *nb = apr_pcalloc(result_pool, sizeof(*nb)); + + SVN_ERR(tb->p1->dir_opened(&(nb->baton1), + skip, + skip_children, + relpath, + left_source, + right_source, + copyfrom_source, + pb ? pb->baton1 : NULL, + tb->p1, + result_pool, + scratch_pool)); + + SVN_ERR(tb->p2->dir_opened(&(nb->baton2), + skip, + skip_children, + relpath, + left_source, + right_source, + copyfrom_source, + pb ? pb->baton2 : NULL, + tb->p2, + result_pool, + scratch_pool)); + + *new_dir_baton = nb; + + return SVN_NO_ERROR; +} + +static svn_error_t * +tee_dir_added(const char *relpath, + const svn_diff_source_t *copyfrom_source, + const svn_diff_source_t *right_source, + /*const*/ apr_hash_t *copyfrom_props, + /*const*/ apr_hash_t *right_props, + void *dir_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + struct tee_baton_t *tb = processor->baton; + struct tee_node_baton_t *db = dir_baton; + + SVN_ERR(tb->p1->dir_added(relpath, + copyfrom_source, + right_source, + copyfrom_props, + right_props, + db->baton1, + tb->p1, + scratch_pool)); + + SVN_ERR(tb->p2->dir_added(relpath, + copyfrom_source, + right_source, + copyfrom_props, + right_props, + db->baton2, + tb->p2, + scratch_pool)); + + return SVN_NO_ERROR; +} + +static svn_error_t * +tee_dir_deleted(const char *relpath, + const svn_diff_source_t *left_source, + /*const*/ apr_hash_t *left_props, + void *dir_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + struct tee_baton_t *tb = processor->baton; + struct tee_node_baton_t *db = dir_baton; + + SVN_ERR(tb->p1->dir_deleted(relpath, + left_source, + left_props, + db->baton1, + tb->p1, + scratch_pool)); + + SVN_ERR(tb->p2->dir_deleted(relpath, + left_source, + left_props, + db->baton2, + tb->p2, + scratch_pool)); + + return SVN_NO_ERROR; +} + +static svn_error_t * +tee_dir_changed(const char *relpath, + const svn_diff_source_t *left_source, + const svn_diff_source_t *right_source, + /*const*/ apr_hash_t *left_props, + /*const*/ apr_hash_t *right_props, + const apr_array_header_t *prop_changes, + void *dir_baton, + const struct svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + struct tee_baton_t *tb = processor->baton; + struct tee_node_baton_t *db = dir_baton; + + SVN_ERR(tb->p1->dir_changed(relpath, + left_source, + right_source, + left_props, + right_props, + prop_changes, + db->baton1, + tb->p1, + scratch_pool)); + + SVN_ERR(tb->p2->dir_changed(relpath, + left_source, + right_source, + left_props, + right_props, + prop_changes, + db->baton2, + tb->p2, + scratch_pool)); + return SVN_NO_ERROR; +} + +static svn_error_t * +tee_dir_closed(const char *relpath, + const svn_diff_source_t *left_source, + const svn_diff_source_t *right_source, + void *dir_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + struct tee_baton_t *tb = processor->baton; + struct tee_node_baton_t *db = dir_baton; + + SVN_ERR(tb->p1->dir_closed(relpath, + left_source, + right_source, + db->baton1, + tb->p1, + scratch_pool)); + + SVN_ERR(tb->p2->dir_closed(relpath, + left_source, + right_source, + db->baton2, + tb->p2, + scratch_pool)); + return SVN_NO_ERROR; +} + +static svn_error_t * +tee_file_opened(void **new_file_baton, + svn_boolean_t *skip, + const char *relpath, + const svn_diff_source_t *left_source, + const svn_diff_source_t *right_source, + const svn_diff_source_t *copyfrom_source, + void *dir_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + struct tee_baton_t *tb = processor->baton; + struct tee_node_baton_t *pb = dir_baton; + struct tee_node_baton_t *nb = apr_pcalloc(result_pool, sizeof(*nb)); + + SVN_ERR(tb->p1->file_opened(&(nb->baton1), + skip, + relpath, + left_source, + right_source, + copyfrom_source, + pb ? pb->baton1 : NULL, + tb->p1, + result_pool, + scratch_pool)); + + SVN_ERR(tb->p2->file_opened(&(nb->baton2), + skip, + relpath, + left_source, + right_source, + copyfrom_source, + pb ? pb->baton2 : NULL, + tb->p2, + result_pool, + scratch_pool)); + + *new_file_baton = nb; + + return SVN_NO_ERROR; +} + +static svn_error_t * +tee_file_added(const char *relpath, + const svn_diff_source_t *copyfrom_source, + const svn_diff_source_t *right_source, + const char *copyfrom_file, + const char *right_file, + /*const*/ apr_hash_t *copyfrom_props, + /*const*/ apr_hash_t *right_props, + void *file_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + struct tee_baton_t *tb = processor->baton; + struct tee_node_baton_t *fb = file_baton; + + SVN_ERR(tb->p1->file_added(relpath, + copyfrom_source, + right_source, + copyfrom_file, + right_file, + copyfrom_props, + right_props, + fb->baton1, + tb->p1, + scratch_pool)); + + SVN_ERR(tb->p2->file_added(relpath, + copyfrom_source, + right_source, + copyfrom_file, + right_file, + copyfrom_props, + right_props, + fb->baton2, + tb->p2, + scratch_pool)); + return SVN_NO_ERROR; +} + +static svn_error_t * +tee_file_deleted(const char *relpath, + const svn_diff_source_t *left_source, + const char *left_file, + /*const*/ apr_hash_t *left_props, + void *file_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + struct tee_baton_t *tb = processor->baton; + struct tee_node_baton_t *fb = file_baton; + + SVN_ERR(tb->p1->file_deleted(relpath, + left_source, + left_file, + left_props, + fb->baton1, + tb->p1, + scratch_pool)); + + SVN_ERR(tb->p2->file_deleted(relpath, + left_source, + left_file, + left_props, + fb->baton2, + tb->p2, + scratch_pool)); + return SVN_NO_ERROR; +} + +static svn_error_t * +tee_file_changed(const char *relpath, + const svn_diff_source_t *left_source, + const svn_diff_source_t *right_source, + const char *left_file, + const char *right_file, + /*const*/ apr_hash_t *left_props, + /*const*/ apr_hash_t *right_props, + svn_boolean_t file_modified, + const apr_array_header_t *prop_changes, + void *file_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + struct tee_baton_t *tb = processor->baton; + struct tee_node_baton_t *fb = file_baton; + + SVN_ERR(tb->p1->file_changed(relpath, + left_source, + right_source, + left_file, + right_file, + left_props, + right_props, + file_modified, + prop_changes, + fb->baton1, + tb->p1, + scratch_pool)); + + SVN_ERR(tb->p2->file_changed(relpath, + left_source, + right_source, + left_file, + right_file, + left_props, + right_props, + file_modified, + prop_changes, + fb->baton2, + tb->p2, + scratch_pool)); + return SVN_NO_ERROR; +} + +static svn_error_t * +tee_file_closed(const char *relpath, + const svn_diff_source_t *left_source, + const svn_diff_source_t *right_source, + void *file_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + struct tee_baton_t *tb = processor->baton; + struct tee_node_baton_t *fb = file_baton; + + SVN_ERR(tb->p1->file_closed(relpath, + left_source, + right_source, + fb->baton1, + tb->p1, + scratch_pool)); + + SVN_ERR(tb->p2->file_closed(relpath, + left_source, + right_source, + fb->baton2, + tb->p2, + scratch_pool)); + + return SVN_NO_ERROR; +} + +static svn_error_t * +tee_node_absent(const char *relpath, + void *dir_baton, + const svn_diff_tree_processor_t *processor, + apr_pool_t *scratch_pool) +{ + struct tee_baton_t *tb = processor->baton; + struct tee_node_baton_t *db = dir_baton; + + SVN_ERR(tb->p1->node_absent(relpath, + db ? db->baton1 : NULL, + tb->p1, + scratch_pool)); + + SVN_ERR(tb->p2->node_absent(relpath, + db ? db->baton2 : NULL, + tb->p2, + scratch_pool)); + + return SVN_NO_ERROR; +} + +const svn_diff_tree_processor_t * +svn_diff__tree_processor_tee_create(const svn_diff_tree_processor_t *processor1, + const svn_diff_tree_processor_t *processor2, + apr_pool_t *result_pool) +{ + struct tee_baton_t *tb = apr_pcalloc(result_pool, sizeof(*tb)); + svn_diff_tree_processor_t *tee; + tb->p1 = processor1; + tb->p2 = processor2; + + tee = svn_diff__tree_processor_create(tb, result_pool); + + tee->dir_opened = tee_dir_opened; + tee->dir_added = tee_dir_added; + tee->dir_deleted = tee_dir_deleted; + tee->dir_changed = tee_dir_changed; + tee->dir_closed = tee_dir_closed; + tee->file_opened = tee_file_opened; + tee->file_added = tee_file_added; + tee->file_deleted = tee_file_deleted; + tee->file_changed = tee_file_changed; + tee->file_closed = tee_file_closed; + tee->node_absent = tee_node_absent; + + return tee; +} + +svn_diff_source_t * +svn_diff__source_create(svn_revnum_t revision, + apr_pool_t *result_pool) +{ + svn_diff_source_t *src = apr_pcalloc(result_pool, sizeof(*src)); + + src->revision = revision; + return src; +} |