blob: d18b242c6343fd351fc73ef7b9f8c05cf48a4781 [file] [log] [blame]
/*
* 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"
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)
{
svn_diff_tree_processor_t *tp = apr_pcalloc(result_pool, sizeof(*tp));
tp->baton = baton;
tp->dir_opened = default_dir_opened;
tp->dir_added = default_dir_added;
tp->dir_deleted = default_dir_deleted;
tp->dir_changed = default_dir_changed;
tp->dir_closed = default_dir_closed;
tp->file_opened = default_file_opened;
tp->file_added = default_file_added;
tp->file_deleted = default_file_deleted;
tp->file_changed = default_file_changed;
tp->file_closed = default_file_closed;
tp->node_absent = default_node_absent;
return tp;
}
struct reverse_tree_baton_t
{
const svn_diff_tree_processor_t *processor;
};
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;
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;
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;
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 (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;
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;
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;
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;
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 (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;
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;
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,
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;
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;
}