1251881Speter/*
2251881Speter * diff_tree.c :  default diff tree processor
3251881Speter *
4251881Speter * ====================================================================
5251881Speter *    Licensed to the Apache Software Foundation (ASF) under one
6251881Speter *    or more contributor license agreements.  See the NOTICE file
7251881Speter *    distributed with this work for additional information
8251881Speter *    regarding copyright ownership.  The ASF licenses this file
9251881Speter *    to you under the Apache License, Version 2.0 (the
10251881Speter *    "License"); you may not use this file except in compliance
11251881Speter *    with the License.  You may obtain a copy of the License at
12251881Speter *
13251881Speter *      http://www.apache.org/licenses/LICENSE-2.0
14251881Speter *
15251881Speter *    Unless required by applicable law or agreed to in writing,
16251881Speter *    software distributed under the License is distributed on an
17251881Speter *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18251881Speter *    KIND, either express or implied.  See the License for the
19251881Speter *    specific language governing permissions and limitations
20251881Speter *    under the License.
21251881Speter * ====================================================================
22251881Speter */
23251881Speter
24251881Speter#include <apr.h>
25251881Speter#include <apr_pools.h>
26251881Speter#include <apr_general.h>
27251881Speter
28251881Speter#include <assert.h>
29251881Speter
30251881Speter#include "svn_dirent_uri.h"
31251881Speter#include "svn_error.h"
32251881Speter#include "svn_io.h"
33251881Speter#include "svn_pools.h"
34251881Speter#include "svn_props.h"
35251881Speter#include "svn_types.h"
36251881Speter
37251881Speter#include "private/svn_diff_tree.h"
38251881Speter#include "svn_private_config.h"
39251881Speter
40251881Spetertypedef struct tree_processor_t
41251881Speter{
42251881Speter  svn_diff_tree_processor_t tp;
43251881Speter
44251881Speter  /* void *future_extension */
45251881Speter} tree_processor_t;
46251881Speter
47251881Speter
48251881Speterstatic svn_error_t *
49251881Speterdefault_dir_opened(void **new_dir_baton,
50251881Speter                   svn_boolean_t *skip,
51251881Speter                   svn_boolean_t *skip_children,
52251881Speter                   const char *relpath,
53251881Speter                   const svn_diff_source_t *left_source,
54251881Speter                   const svn_diff_source_t *right_source,
55251881Speter                   const svn_diff_source_t *copyfrom_source,
56251881Speter                   void *parent_dir_baton,
57251881Speter                   const svn_diff_tree_processor_t *processor,
58251881Speter                   apr_pool_t *result_pool,
59251881Speter                   apr_pool_t *scratch_pool)
60251881Speter{
61251881Speter  *new_dir_baton = NULL;
62251881Speter  return SVN_NO_ERROR;
63251881Speter}
64251881Speter
65251881Speterstatic svn_error_t *
66251881Speterdefault_dir_added(const char *relpath,
67251881Speter                  const svn_diff_source_t *copyfrom_source,
68251881Speter                  const svn_diff_source_t *right_source,
69251881Speter                  /*const*/ apr_hash_t *copyfrom_props,
70251881Speter                  /*const*/ apr_hash_t *right_props,
71251881Speter                  void *dir_baton,
72251881Speter                  const svn_diff_tree_processor_t *processor,
73251881Speter                  apr_pool_t *scratch_pool)
74251881Speter{
75251881Speter  SVN_ERR(processor->dir_closed(relpath, NULL, right_source,
76251881Speter                                dir_baton, processor,
77251881Speter                                scratch_pool));
78251881Speter
79251881Speter  return SVN_NO_ERROR;
80251881Speter}
81251881Speter
82251881Speterstatic svn_error_t *
83251881Speterdefault_dir_deleted(const char *relpath,
84251881Speter                    const svn_diff_source_t *left_source,
85251881Speter                    /*const*/ apr_hash_t *left_props,
86251881Speter                    void *dir_baton,
87251881Speter                    const svn_diff_tree_processor_t *processor,
88251881Speter                    apr_pool_t *scratch_pool)
89251881Speter{
90251881Speter  SVN_ERR(processor->dir_closed(relpath, left_source, NULL,
91251881Speter                                dir_baton, processor,
92251881Speter                                scratch_pool));
93251881Speter  return SVN_NO_ERROR;
94251881Speter}
95251881Speter
96251881Speterstatic svn_error_t *
97251881Speterdefault_dir_changed(const char *relpath,
98251881Speter                    const svn_diff_source_t *left_source,
99251881Speter                    const svn_diff_source_t *right_source,
100251881Speter                    /*const*/ apr_hash_t *left_props,
101251881Speter                    /*const*/ apr_hash_t *right_props,
102251881Speter                    const apr_array_header_t *prop_changes,
103251881Speter                    void *dir_baton,
104251881Speter                    const struct svn_diff_tree_processor_t *processor,
105251881Speter                    apr_pool_t *scratch_pool)
106251881Speter{
107251881Speter  SVN_ERR(processor->dir_closed(relpath,
108251881Speter                                left_source, right_source,
109251881Speter                                dir_baton,
110251881Speter                                processor, scratch_pool));
111251881Speter  return SVN_NO_ERROR;
112251881Speter}
113251881Speter
114251881Speterstatic svn_error_t *
115251881Speterdefault_dir_closed(const char *relpath,
116251881Speter                   const svn_diff_source_t *left_source,
117251881Speter                   const svn_diff_source_t *right_source,
118251881Speter                   void *dir_baton,
119251881Speter                   const svn_diff_tree_processor_t *processor,
120251881Speter                   apr_pool_t *scratch_pool)
121251881Speter{
122251881Speter  return SVN_NO_ERROR;
123251881Speter}
124251881Speter
125251881Speterstatic svn_error_t *
126251881Speterdefault_file_opened(void **new_file_baton,
127251881Speter                    svn_boolean_t *skip,
128251881Speter                    const char *relpath,
129251881Speter                    const svn_diff_source_t *left_source,
130251881Speter                    const svn_diff_source_t *right_source,
131251881Speter                    const svn_diff_source_t *copyfrom_source,
132251881Speter                    void *dir_baton,
133251881Speter                    const svn_diff_tree_processor_t *processor,
134251881Speter                    apr_pool_t *result_pool,
135251881Speter                    apr_pool_t *scratch_pool)
136251881Speter{
137251881Speter  *new_file_baton = dir_baton;
138251881Speter  return SVN_NO_ERROR;
139251881Speter}
140251881Speter
141251881Speterstatic svn_error_t *
142251881Speterdefault_file_added(const char *relpath,
143251881Speter                   const svn_diff_source_t *copyfrom_source,
144251881Speter                   const svn_diff_source_t *right_source,
145251881Speter                   const char *copyfrom_file,
146251881Speter                   const char *right_file,
147251881Speter                   /*const*/ apr_hash_t *copyfrom_props,
148251881Speter                   /*const*/ apr_hash_t *right_props,
149251881Speter                   void *file_baton,
150251881Speter                   const svn_diff_tree_processor_t *processor,
151251881Speter                   apr_pool_t *scratch_pool)
152251881Speter{
153251881Speter  SVN_ERR(processor->file_closed(relpath,
154251881Speter                                 NULL, right_source,
155251881Speter                                 file_baton, processor, scratch_pool));
156251881Speter  return SVN_NO_ERROR;
157251881Speter}
158251881Speter
159251881Speterstatic svn_error_t *
160251881Speterdefault_file_deleted(const char *relpath,
161251881Speter                     const svn_diff_source_t *left_source,
162251881Speter                     const char *left_file,
163251881Speter                     /*const*/ apr_hash_t *left_props,
164251881Speter                     void *file_baton,
165251881Speter                     const svn_diff_tree_processor_t *processor,
166251881Speter                     apr_pool_t *scratch_pool)
167251881Speter{
168251881Speter  SVN_ERR(processor->file_closed(relpath,
169251881Speter                                 left_source, NULL,
170251881Speter                                 file_baton, processor, scratch_pool));
171251881Speter  return SVN_NO_ERROR;
172251881Speter}
173251881Speter
174251881Speterstatic svn_error_t *
175251881Speterdefault_file_changed(const char *relpath,
176251881Speter                     const svn_diff_source_t *left_source,
177251881Speter                     const svn_diff_source_t *right_source,
178251881Speter                     const char *left_file,
179251881Speter                     const char *right_file,
180251881Speter                     /*const*/ apr_hash_t *left_props,
181251881Speter                     /*const*/ apr_hash_t *right_props,
182251881Speter                     svn_boolean_t file_modified,
183251881Speter                     const apr_array_header_t *prop_changes,
184251881Speter                     void *file_baton,
185251881Speter                     const svn_diff_tree_processor_t *processor,
186251881Speter                     apr_pool_t *scratch_pool)
187251881Speter{
188251881Speter  SVN_ERR(processor->file_closed(relpath,
189251881Speter                                 left_source, right_source,
190251881Speter                                 file_baton, processor, scratch_pool));
191251881Speter  return SVN_NO_ERROR;
192251881Speter}
193251881Speter
194251881Speterstatic svn_error_t *
195251881Speterdefault_file_closed(const char *relpath,
196251881Speter                    const svn_diff_source_t *left_source,
197251881Speter                    const svn_diff_source_t *right_source,
198251881Speter                    void *file_baton,
199251881Speter                    const svn_diff_tree_processor_t *processor,
200251881Speter                    apr_pool_t *scratch_pool)
201251881Speter{
202251881Speter  return SVN_NO_ERROR;
203251881Speter}
204251881Speter
205251881Speterstatic svn_error_t *
206251881Speterdefault_node_absent(const char *relpath,
207251881Speter                    void *dir_baton,
208251881Speter                    const svn_diff_tree_processor_t *processor,
209251881Speter                    apr_pool_t *scratch_pool)
210251881Speter{
211251881Speter  return SVN_NO_ERROR;
212251881Speter}
213251881Speter
214251881Spetersvn_diff_tree_processor_t *
215251881Spetersvn_diff__tree_processor_create(void *baton,
216251881Speter                                apr_pool_t *result_pool)
217251881Speter{
218251881Speter  tree_processor_t *wrapper;
219251881Speter  wrapper = apr_pcalloc(result_pool, sizeof(*wrapper));
220251881Speter
221251881Speter  wrapper->tp.baton        = baton;
222251881Speter
223251881Speter  wrapper->tp.dir_opened   = default_dir_opened;
224251881Speter  wrapper->tp.dir_added    = default_dir_added;
225251881Speter  wrapper->tp.dir_deleted  = default_dir_deleted;
226251881Speter  wrapper->tp.dir_changed  = default_dir_changed;
227251881Speter  wrapper->tp.dir_closed   = default_dir_closed;
228251881Speter
229251881Speter  wrapper->tp.file_opened   = default_file_opened;
230251881Speter  wrapper->tp.file_added    = default_file_added;
231251881Speter  wrapper->tp.file_deleted  = default_file_deleted;
232251881Speter  wrapper->tp.file_changed  = default_file_changed;
233251881Speter  wrapper->tp.file_closed   = default_file_closed;
234251881Speter
235251881Speter  wrapper->tp.node_absent   = default_node_absent;
236251881Speter
237251881Speter
238251881Speter  return &wrapper->tp;
239251881Speter}
240251881Speter
241251881Speterstruct reverse_tree_baton_t
242251881Speter{
243251881Speter  const svn_diff_tree_processor_t *processor;
244251881Speter  const char *prefix_relpath;
245251881Speter};
246251881Speter
247251881Speterstatic svn_error_t *
248251881Speterreverse_dir_opened(void **new_dir_baton,
249251881Speter                   svn_boolean_t *skip,
250251881Speter                   svn_boolean_t *skip_children,
251251881Speter                   const char *relpath,
252251881Speter                   const svn_diff_source_t *left_source,
253251881Speter                   const svn_diff_source_t *right_source,
254251881Speter                   const svn_diff_source_t *copyfrom_source,
255251881Speter                   void *parent_dir_baton,
256251881Speter                   const svn_diff_tree_processor_t *processor,
257251881Speter                   apr_pool_t *result_pool,
258251881Speter                   apr_pool_t *scratch_pool)
259251881Speter{
260251881Speter  struct reverse_tree_baton_t *rb = processor->baton;
261251881Speter
262251881Speter  if (rb->prefix_relpath)
263251881Speter    relpath = svn_relpath_join(rb->prefix_relpath, relpath, scratch_pool);
264251881Speter
265251881Speter  SVN_ERR(rb->processor->dir_opened(new_dir_baton, skip, skip_children,
266251881Speter                                    relpath,
267251881Speter                                    right_source, left_source,
268251881Speter                                    NULL /* copyfrom */,
269251881Speter                                    parent_dir_baton,
270251881Speter                                    rb->processor,
271251881Speter                                    result_pool, scratch_pool));
272251881Speter  return SVN_NO_ERROR;
273251881Speter}
274251881Speter
275251881Speterstatic svn_error_t *
276251881Speterreverse_dir_added(const char *relpath,
277251881Speter                  const svn_diff_source_t *copyfrom_source,
278251881Speter                  const svn_diff_source_t *right_source,
279251881Speter                  /*const*/ apr_hash_t *copyfrom_props,
280251881Speter                  /*const*/ apr_hash_t *right_props,
281251881Speter                  void *dir_baton,
282251881Speter                  const svn_diff_tree_processor_t *processor,
283251881Speter                  apr_pool_t *scratch_pool)
284251881Speter{
285251881Speter  struct reverse_tree_baton_t *rb = processor->baton;
286251881Speter
287251881Speter  if (rb->prefix_relpath)
288251881Speter    relpath = svn_relpath_join(rb->prefix_relpath, relpath, scratch_pool);
289251881Speter
290251881Speter  SVN_ERR(rb->processor->dir_deleted(relpath,
291251881Speter                                     right_source,
292251881Speter                                     right_props,
293251881Speter                                     dir_baton,
294251881Speter                                     rb->processor,
295251881Speter                                     scratch_pool));
296251881Speter
297251881Speter  return SVN_NO_ERROR;
298251881Speter}
299251881Speter
300251881Speterstatic svn_error_t *
301251881Speterreverse_dir_deleted(const char *relpath,
302251881Speter                    const svn_diff_source_t *left_source,
303251881Speter                    /*const*/ apr_hash_t *left_props,
304251881Speter                    void *dir_baton,
305251881Speter                    const svn_diff_tree_processor_t *processor,
306251881Speter                    apr_pool_t *scratch_pool)
307251881Speter{
308251881Speter  struct reverse_tree_baton_t *rb = processor->baton;
309251881Speter
310251881Speter  if (rb->prefix_relpath)
311251881Speter    relpath = svn_relpath_join(rb->prefix_relpath, relpath, scratch_pool);
312251881Speter
313251881Speter  SVN_ERR(rb->processor->dir_added(relpath,
314251881Speter                                   NULL,
315251881Speter                                   left_source,
316251881Speter                                   NULL,
317251881Speter                                   left_props,
318251881Speter                                   dir_baton,
319251881Speter                                   rb->processor,
320251881Speter                                   scratch_pool));
321251881Speter  return SVN_NO_ERROR;
322251881Speter}
323251881Speter
324251881Speterstatic svn_error_t *
325251881Speterreverse_dir_changed(const char *relpath,
326251881Speter                    const svn_diff_source_t *left_source,
327251881Speter                    const svn_diff_source_t *right_source,
328251881Speter                    /*const*/ apr_hash_t *left_props,
329251881Speter                    /*const*/ apr_hash_t *right_props,
330251881Speter                    const apr_array_header_t *prop_changes,
331251881Speter                    void *dir_baton,
332251881Speter                    const struct svn_diff_tree_processor_t *processor,
333251881Speter                    apr_pool_t *scratch_pool)
334251881Speter{
335251881Speter  struct reverse_tree_baton_t *rb = processor->baton;
336251881Speter  apr_array_header_t *reversed_prop_changes = NULL;
337251881Speter
338251881Speter  if (rb->prefix_relpath)
339251881Speter    relpath = svn_relpath_join(rb->prefix_relpath, relpath, scratch_pool);
340251881Speter
341251881Speter  if (prop_changes)
342251881Speter    {
343251881Speter      SVN_ERR_ASSERT(left_props != NULL && right_props != NULL);
344251881Speter      SVN_ERR(svn_prop_diffs(&reversed_prop_changes, left_props, right_props,
345251881Speter                             scratch_pool));
346251881Speter    }
347251881Speter
348251881Speter  SVN_ERR(rb->processor->dir_changed(relpath,
349251881Speter                                     right_source,
350251881Speter                                     left_source,
351251881Speter                                     right_props,
352251881Speter                                     left_props,
353251881Speter                                     reversed_prop_changes,
354251881Speter                                     dir_baton,
355251881Speter                                     rb->processor,
356251881Speter                                     scratch_pool));
357251881Speter  return SVN_NO_ERROR;
358251881Speter}
359251881Speter
360251881Speterstatic svn_error_t *
361251881Speterreverse_dir_closed(const char *relpath,
362251881Speter                   const svn_diff_source_t *left_source,
363251881Speter                   const svn_diff_source_t *right_source,
364251881Speter                   void *dir_baton,
365251881Speter                   const svn_diff_tree_processor_t *processor,
366251881Speter                   apr_pool_t *scratch_pool)
367251881Speter{
368251881Speter  struct reverse_tree_baton_t *rb = processor->baton;
369251881Speter
370251881Speter  if (rb->prefix_relpath)
371251881Speter    relpath = svn_relpath_join(rb->prefix_relpath, relpath, scratch_pool);
372251881Speter
373251881Speter  SVN_ERR(rb->processor->dir_closed(relpath,
374251881Speter                                    right_source,
375251881Speter                                    left_source,
376251881Speter                                    dir_baton,
377251881Speter                                    rb->processor,
378251881Speter                                    scratch_pool));
379251881Speter  return SVN_NO_ERROR;
380251881Speter}
381251881Speter
382251881Speterstatic svn_error_t *
383251881Speterreverse_file_opened(void **new_file_baton,
384251881Speter                    svn_boolean_t *skip,
385251881Speter                    const char *relpath,
386251881Speter                    const svn_diff_source_t *left_source,
387251881Speter                    const svn_diff_source_t *right_source,
388251881Speter                    const svn_diff_source_t *copyfrom_source,
389251881Speter                    void *dir_baton,
390251881Speter                    const svn_diff_tree_processor_t *processor,
391251881Speter                    apr_pool_t *result_pool,
392251881Speter                    apr_pool_t *scratch_pool)
393251881Speter{
394251881Speter  struct reverse_tree_baton_t *rb = processor->baton;
395251881Speter
396251881Speter  if (rb->prefix_relpath)
397251881Speter    relpath = svn_relpath_join(rb->prefix_relpath, relpath, scratch_pool);
398251881Speter
399251881Speter  SVN_ERR(rb->processor->file_opened(new_file_baton,
400251881Speter                                     skip,
401251881Speter                                     relpath,
402251881Speter                                     right_source,
403251881Speter                                     left_source,
404251881Speter                                     NULL /* copy_from */,
405251881Speter                                     dir_baton,
406251881Speter                                     rb->processor,
407251881Speter                                     result_pool,
408251881Speter                                     scratch_pool));
409251881Speter  return SVN_NO_ERROR;
410251881Speter}
411251881Speter
412251881Speterstatic svn_error_t *
413251881Speterreverse_file_added(const char *relpath,
414251881Speter                   const svn_diff_source_t *copyfrom_source,
415251881Speter                   const svn_diff_source_t *right_source,
416251881Speter                   const char *copyfrom_file,
417251881Speter                   const char *right_file,
418251881Speter                   /*const*/ apr_hash_t *copyfrom_props,
419251881Speter                   /*const*/ apr_hash_t *right_props,
420251881Speter                   void *file_baton,
421251881Speter                   const svn_diff_tree_processor_t *processor,
422251881Speter                   apr_pool_t *scratch_pool)
423251881Speter{
424251881Speter  struct reverse_tree_baton_t *rb = processor->baton;
425251881Speter
426251881Speter  if (rb->prefix_relpath)
427251881Speter    relpath = svn_relpath_join(rb->prefix_relpath, relpath, scratch_pool);
428251881Speter
429251881Speter  SVN_ERR(rb->processor->file_deleted(relpath,
430251881Speter                                      right_source,
431251881Speter                                      right_file,
432251881Speter                                      right_props,
433251881Speter                                      file_baton,
434251881Speter                                      rb->processor,
435251881Speter                                      scratch_pool));
436251881Speter  return SVN_NO_ERROR;
437251881Speter}
438251881Speter
439251881Speterstatic svn_error_t *
440251881Speterreverse_file_deleted(const char *relpath,
441251881Speter                     const svn_diff_source_t *left_source,
442251881Speter                     const char *left_file,
443251881Speter                     /*const*/ apr_hash_t *left_props,
444251881Speter                     void *file_baton,
445251881Speter                     const svn_diff_tree_processor_t *processor,
446251881Speter                     apr_pool_t *scratch_pool)
447251881Speter{
448251881Speter  struct reverse_tree_baton_t *rb = processor->baton;
449251881Speter
450251881Speter  if (rb->prefix_relpath)
451251881Speter    relpath = svn_relpath_join(rb->prefix_relpath, relpath, scratch_pool);
452251881Speter
453251881Speter  SVN_ERR(rb->processor->file_added(relpath,
454251881Speter                                    NULL /* copyfrom src */,
455251881Speter                                    left_source,
456251881Speter                                    NULL /* copyfrom file */,
457251881Speter                                    left_file,
458251881Speter                                    NULL /* copyfrom props */,
459251881Speter                                    left_props,
460251881Speter                                    file_baton,
461251881Speter                                    rb->processor,
462251881Speter                                    scratch_pool));
463251881Speter  return SVN_NO_ERROR;
464251881Speter}
465251881Speter
466251881Speterstatic svn_error_t *
467251881Speterreverse_file_changed(const char *relpath,
468251881Speter                     const svn_diff_source_t *left_source,
469251881Speter                     const svn_diff_source_t *right_source,
470251881Speter                     const char *left_file,
471251881Speter                     const char *right_file,
472251881Speter                     /*const*/ apr_hash_t *left_props,
473251881Speter                     /*const*/ apr_hash_t *right_props,
474251881Speter                     svn_boolean_t file_modified,
475251881Speter                     const apr_array_header_t *prop_changes,
476251881Speter                     void *file_baton,
477251881Speter                     const svn_diff_tree_processor_t *processor,
478251881Speter                     apr_pool_t *scratch_pool)
479251881Speter{
480251881Speter  struct reverse_tree_baton_t *rb = processor->baton;
481251881Speter  apr_array_header_t *reversed_prop_changes = NULL;
482251881Speter
483251881Speter  if (rb->prefix_relpath)
484251881Speter    relpath = svn_relpath_join(rb->prefix_relpath, relpath, scratch_pool);
485251881Speter
486251881Speter  if (prop_changes)
487251881Speter    {
488251881Speter      SVN_ERR_ASSERT(left_props != NULL && right_props != NULL);
489251881Speter      SVN_ERR(svn_prop_diffs(&reversed_prop_changes, left_props, right_props,
490251881Speter                             scratch_pool));
491251881Speter    }
492251881Speter
493251881Speter  SVN_ERR(rb->processor->file_changed(relpath,
494251881Speter                                      right_source,
495251881Speter                                      left_source,
496251881Speter                                      right_file,
497251881Speter                                      left_file,
498251881Speter                                      right_props,
499251881Speter                                      left_props,
500251881Speter                                      file_modified,
501251881Speter                                      reversed_prop_changes,
502251881Speter                                      file_baton,
503251881Speter                                      rb->processor,
504251881Speter                                      scratch_pool));
505251881Speter  return SVN_NO_ERROR;
506251881Speter}
507251881Speter
508251881Speterstatic svn_error_t *
509251881Speterreverse_file_closed(const char *relpath,
510251881Speter                    const svn_diff_source_t *left_source,
511251881Speter                    const svn_diff_source_t *right_source,
512251881Speter                    void *file_baton,
513251881Speter                    const svn_diff_tree_processor_t *processor,
514251881Speter                    apr_pool_t *scratch_pool)
515251881Speter{
516251881Speter  struct reverse_tree_baton_t *rb = processor->baton;
517251881Speter
518251881Speter  if (rb->prefix_relpath)
519251881Speter    relpath = svn_relpath_join(rb->prefix_relpath, relpath, scratch_pool);
520251881Speter
521251881Speter  SVN_ERR(rb->processor->file_closed(relpath,
522251881Speter                                     right_source,
523251881Speter                                     left_source,
524251881Speter                                     file_baton,
525251881Speter                                     rb->processor,
526251881Speter                                     scratch_pool));
527251881Speter
528251881Speter  return SVN_NO_ERROR;
529251881Speter}
530251881Speter
531251881Speterstatic svn_error_t *
532251881Speterreverse_node_absent(const char *relpath,
533251881Speter                    void *dir_baton,
534251881Speter                    const svn_diff_tree_processor_t *processor,
535251881Speter                    apr_pool_t *scratch_pool)
536251881Speter{
537251881Speter  struct reverse_tree_baton_t *rb = processor->baton;
538251881Speter
539251881Speter  if (rb->prefix_relpath)
540251881Speter    relpath = svn_relpath_join(rb->prefix_relpath, relpath, scratch_pool);
541251881Speter
542251881Speter  SVN_ERR(rb->processor->node_absent(relpath,
543251881Speter                                    dir_baton,
544251881Speter                                    rb->processor,
545251881Speter                                    scratch_pool));
546251881Speter  return SVN_NO_ERROR;
547251881Speter}
548251881Speter
549251881Speter
550251881Speterconst svn_diff_tree_processor_t *
551251881Spetersvn_diff__tree_processor_reverse_create(const svn_diff_tree_processor_t * processor,
552251881Speter                                        const char *prefix_relpath,
553251881Speter                                        apr_pool_t *result_pool)
554251881Speter{
555251881Speter  struct reverse_tree_baton_t *rb;
556251881Speter  svn_diff_tree_processor_t *reverse;
557251881Speter
558251881Speter  rb = apr_pcalloc(result_pool, sizeof(*rb));
559251881Speter  rb->processor = processor;
560251881Speter  if (prefix_relpath)
561251881Speter    rb->prefix_relpath = apr_pstrdup(result_pool, prefix_relpath);
562251881Speter
563251881Speter  reverse = svn_diff__tree_processor_create(rb, result_pool);
564251881Speter
565251881Speter  reverse->dir_opened   = reverse_dir_opened;
566251881Speter  reverse->dir_added    = reverse_dir_added;
567251881Speter  reverse->dir_deleted  = reverse_dir_deleted;
568251881Speter  reverse->dir_changed  = reverse_dir_changed;
569251881Speter  reverse->dir_closed   = reverse_dir_closed;
570251881Speter
571251881Speter  reverse->file_opened   = reverse_file_opened;
572251881Speter  reverse->file_added    = reverse_file_added;
573251881Speter  reverse->file_deleted  = reverse_file_deleted;
574251881Speter  reverse->file_changed  = reverse_file_changed;
575251881Speter  reverse->file_closed   = reverse_file_closed;
576251881Speter
577251881Speter  reverse->node_absent   = reverse_node_absent;
578251881Speter
579251881Speter  return reverse;
580251881Speter}
581251881Speter
582251881Speterstruct filter_tree_baton_t
583251881Speter{
584251881Speter  const svn_diff_tree_processor_t *processor;
585251881Speter  const char *prefix_relpath;
586251881Speter};
587251881Speter
588251881Speterstatic svn_error_t *
589251881Speterfilter_dir_opened(void **new_dir_baton,
590251881Speter                  svn_boolean_t *skip,
591251881Speter                  svn_boolean_t *skip_children,
592251881Speter                  const char *relpath,
593251881Speter                  const svn_diff_source_t *left_source,
594251881Speter                  const svn_diff_source_t *right_source,
595251881Speter                  const svn_diff_source_t *copyfrom_source,
596251881Speter                  void *parent_dir_baton,
597251881Speter                  const svn_diff_tree_processor_t *processor,
598251881Speter                  apr_pool_t *result_pool,
599251881Speter                  apr_pool_t *scratch_pool)
600251881Speter{
601251881Speter  struct filter_tree_baton_t *fb = processor->baton;
602251881Speter
603251881Speter  relpath = svn_relpath_skip_ancestor(fb->prefix_relpath, relpath);
604251881Speter
605251881Speter  if (! relpath)
606251881Speter    {
607251881Speter      /* Skip work for this, but NOT for DESCENDANTS */
608251881Speter      *skip = TRUE;
609251881Speter      return SVN_NO_ERROR;
610251881Speter    }
611251881Speter
612251881Speter  SVN_ERR(fb->processor->dir_opened(new_dir_baton, skip, skip_children,
613251881Speter                                    relpath,
614251881Speter                                    left_source, right_source,
615251881Speter                                    copyfrom_source,
616251881Speter                                    parent_dir_baton,
617251881Speter                                    fb->processor,
618251881Speter                                    result_pool, scratch_pool));
619251881Speter  return SVN_NO_ERROR;
620251881Speter}
621251881Speter
622251881Speterstatic svn_error_t *
623251881Speterfilter_dir_added(const char *relpath,
624251881Speter                 const svn_diff_source_t *copyfrom_source,
625251881Speter                 const svn_diff_source_t *right_source,
626251881Speter                 /*const*/ apr_hash_t *copyfrom_props,
627251881Speter                 /*const*/ apr_hash_t *right_props,
628251881Speter                 void *dir_baton,
629251881Speter                 const svn_diff_tree_processor_t *processor,
630251881Speter                 apr_pool_t *scratch_pool)
631251881Speter{
632251881Speter  struct filter_tree_baton_t *fb = processor->baton;
633251881Speter
634251881Speter  relpath = svn_relpath_skip_ancestor(fb->prefix_relpath, relpath);
635251881Speter  assert(relpath != NULL); /* Driver error */
636251881Speter
637251881Speter  SVN_ERR(fb->processor->dir_added(relpath,
638251881Speter                                   copyfrom_source,
639251881Speter                                   right_source,
640251881Speter                                   copyfrom_props,
641251881Speter                                   right_props,
642251881Speter                                   dir_baton,
643251881Speter                                   fb->processor,
644251881Speter                                   scratch_pool));
645251881Speter
646251881Speter  return SVN_NO_ERROR;
647251881Speter}
648251881Speter
649251881Speterstatic svn_error_t *
650251881Speterfilter_dir_deleted(const char *relpath,
651251881Speter                   const svn_diff_source_t *left_source,
652251881Speter                   /*const*/ apr_hash_t *left_props,
653251881Speter                   void *dir_baton,
654251881Speter                   const svn_diff_tree_processor_t *processor,
655251881Speter                   apr_pool_t *scratch_pool)
656251881Speter{
657251881Speter  struct filter_tree_baton_t *fb = processor->baton;
658251881Speter
659251881Speter  relpath = svn_relpath_skip_ancestor(fb->prefix_relpath, relpath);
660251881Speter  assert(relpath != NULL); /* Driver error */
661251881Speter
662251881Speter  SVN_ERR(fb->processor->dir_deleted(relpath,
663251881Speter                                     left_source,
664251881Speter                                     left_props,
665251881Speter                                     dir_baton,
666251881Speter                                     fb->processor,
667251881Speter                                     scratch_pool));
668251881Speter
669251881Speter  return SVN_NO_ERROR;
670251881Speter}
671251881Speter
672251881Speterstatic svn_error_t *
673251881Speterfilter_dir_changed(const char *relpath,
674251881Speter                   const svn_diff_source_t *left_source,
675251881Speter                   const svn_diff_source_t *right_source,
676251881Speter                   /*const*/ apr_hash_t *left_props,
677251881Speter                   /*const*/ apr_hash_t *right_props,
678251881Speter                   const apr_array_header_t *prop_changes,
679251881Speter                   void *dir_baton,
680251881Speter                   const struct svn_diff_tree_processor_t *processor,
681251881Speter                   apr_pool_t *scratch_pool)
682251881Speter{
683251881Speter  struct filter_tree_baton_t *fb = processor->baton;
684251881Speter
685251881Speter  relpath = svn_relpath_skip_ancestor(fb->prefix_relpath, relpath);
686251881Speter  assert(relpath != NULL); /* Driver error */
687251881Speter
688251881Speter  SVN_ERR(fb->processor->dir_changed(relpath,
689251881Speter                                     left_source,
690251881Speter                                     right_source,
691251881Speter                                     left_props,
692251881Speter                                     right_props,
693251881Speter                                     prop_changes,
694251881Speter                                     dir_baton,
695251881Speter                                     fb->processor,
696251881Speter                                     scratch_pool));
697251881Speter  return SVN_NO_ERROR;
698251881Speter}
699251881Speter
700251881Speterstatic svn_error_t *
701251881Speterfilter_dir_closed(const char *relpath,
702251881Speter                  const svn_diff_source_t *left_source,
703251881Speter                  const svn_diff_source_t *right_source,
704251881Speter                  void *dir_baton,
705251881Speter                  const svn_diff_tree_processor_t *processor,
706251881Speter                  apr_pool_t *scratch_pool)
707251881Speter{
708251881Speter  struct filter_tree_baton_t *fb = processor->baton;
709251881Speter
710251881Speter  relpath = svn_relpath_skip_ancestor(fb->prefix_relpath, relpath);
711251881Speter  assert(relpath != NULL); /* Driver error */
712251881Speter
713251881Speter  SVN_ERR(fb->processor->dir_closed(relpath,
714251881Speter                                    left_source,
715251881Speter                                    right_source,
716251881Speter                                    dir_baton,
717251881Speter                                    fb->processor,
718251881Speter                                    scratch_pool));
719251881Speter  return SVN_NO_ERROR;
720251881Speter}
721251881Speter
722251881Speterstatic svn_error_t *
723251881Speterfilter_file_opened(void **new_file_baton,
724251881Speter                   svn_boolean_t *skip,
725251881Speter                   const char *relpath,
726251881Speter                   const svn_diff_source_t *left_source,
727251881Speter                   const svn_diff_source_t *right_source,
728251881Speter                   const svn_diff_source_t *copyfrom_source,
729251881Speter                   void *dir_baton,
730251881Speter                   const svn_diff_tree_processor_t *processor,
731251881Speter                   apr_pool_t *result_pool,
732251881Speter                   apr_pool_t *scratch_pool)
733251881Speter{
734251881Speter  struct filter_tree_baton_t *fb = processor->baton;
735251881Speter
736251881Speter  relpath = svn_relpath_skip_ancestor(fb->prefix_relpath, relpath);
737251881Speter
738251881Speter  if (! relpath)
739251881Speter    {
740251881Speter      *skip = TRUE;
741251881Speter      return SVN_NO_ERROR;
742251881Speter    }
743251881Speter
744251881Speter  SVN_ERR(fb->processor->file_opened(new_file_baton,
745251881Speter                                     skip,
746251881Speter                                     relpath,
747251881Speter                                     left_source,
748251881Speter                                     right_source,
749251881Speter                                     copyfrom_source,
750251881Speter                                     dir_baton,
751251881Speter                                     fb->processor,
752251881Speter                                     result_pool,
753251881Speter                                     scratch_pool));
754251881Speter  return SVN_NO_ERROR;
755251881Speter}
756251881Speter
757251881Speterstatic svn_error_t *
758251881Speterfilter_file_added(const char *relpath,
759251881Speter                  const svn_diff_source_t *copyfrom_source,
760251881Speter                  const svn_diff_source_t *right_source,
761251881Speter                  const char *copyfrom_file,
762251881Speter                  const char *right_file,
763251881Speter                  /*const*/ apr_hash_t *copyfrom_props,
764251881Speter                  /*const*/ apr_hash_t *right_props,
765251881Speter                  void *file_baton,
766251881Speter                  const svn_diff_tree_processor_t *processor,
767251881Speter                  apr_pool_t *scratch_pool)
768251881Speter{
769251881Speter  struct filter_tree_baton_t *fb = processor->baton;
770251881Speter
771251881Speter  relpath = svn_relpath_skip_ancestor(fb->prefix_relpath, relpath);
772251881Speter  assert(relpath != NULL); /* Driver error */
773251881Speter
774251881Speter  SVN_ERR(fb->processor->file_added(relpath,
775251881Speter                                    copyfrom_source,
776251881Speter                                    right_source,
777251881Speter                                    copyfrom_file,
778251881Speter                                    right_file,
779251881Speter                                    copyfrom_props,
780251881Speter                                    right_props,
781251881Speter                                    file_baton,
782251881Speter                                    fb->processor,
783251881Speter                                    scratch_pool));
784251881Speter  return SVN_NO_ERROR;
785251881Speter}
786251881Speter
787251881Speterstatic svn_error_t *
788251881Speterfilter_file_deleted(const char *relpath,
789251881Speter                    const svn_diff_source_t *left_source,
790251881Speter                    const char *left_file,
791251881Speter                    /*const*/ apr_hash_t *left_props,
792251881Speter                    void *file_baton,
793251881Speter                    const svn_diff_tree_processor_t *processor,
794251881Speter                    apr_pool_t *scratch_pool)
795251881Speter{
796251881Speter  struct filter_tree_baton_t *fb = processor->baton;
797251881Speter
798251881Speter  relpath = svn_relpath_skip_ancestor(fb->prefix_relpath, relpath);
799251881Speter  assert(relpath != NULL); /* Driver error */
800251881Speter
801251881Speter  SVN_ERR(fb->processor->file_deleted(relpath,
802251881Speter                                      left_source,
803251881Speter                                      left_file,
804251881Speter                                      left_props,
805251881Speter                                      file_baton,
806251881Speter                                      fb->processor,
807251881Speter                                      scratch_pool));
808251881Speter
809251881Speter  return SVN_NO_ERROR;
810251881Speter}
811251881Speter
812251881Speterstatic svn_error_t *
813251881Speterfilter_file_changed(const char *relpath,
814251881Speter                    const svn_diff_source_t *left_source,
815251881Speter                    const svn_diff_source_t *right_source,
816251881Speter                    const char *left_file,
817251881Speter                    const char *right_file,
818251881Speter                    /*const*/ apr_hash_t *left_props,
819251881Speter                    /*const*/ apr_hash_t *right_props,
820251881Speter                    svn_boolean_t file_modified,
821251881Speter                    const apr_array_header_t *prop_changes,
822251881Speter                    void *file_baton,
823251881Speter                    const svn_diff_tree_processor_t *processor,
824251881Speter                    apr_pool_t *scratch_pool)
825251881Speter{
826251881Speter  struct filter_tree_baton_t *fb = processor->baton;
827251881Speter
828251881Speter  relpath = svn_relpath_skip_ancestor(fb->prefix_relpath, relpath);
829251881Speter  assert(relpath != NULL); /* Driver error */
830251881Speter
831251881Speter  SVN_ERR(fb->processor->file_changed(relpath,
832251881Speter                                      left_source,
833251881Speter                                      right_source,
834251881Speter                                      left_file,
835251881Speter                                      right_file,
836251881Speter                                      left_props,
837251881Speter                                      right_props,
838251881Speter                                      file_modified,
839251881Speter                                      prop_changes,
840251881Speter                                      file_baton,
841251881Speter                                      fb->processor,
842251881Speter                                      scratch_pool));
843251881Speter  return SVN_NO_ERROR;
844251881Speter}
845251881Speter
846251881Speterstatic svn_error_t *
847251881Speterfilter_file_closed(const char *relpath,
848251881Speter                   const svn_diff_source_t *left_source,
849251881Speter                   const svn_diff_source_t *right_source,
850251881Speter                   void *file_baton,
851251881Speter                   const svn_diff_tree_processor_t *processor,
852251881Speter                   apr_pool_t *scratch_pool)
853251881Speter{
854251881Speter  struct filter_tree_baton_t *fb = processor->baton;
855251881Speter
856251881Speter  relpath = svn_relpath_skip_ancestor(fb->prefix_relpath, relpath);
857251881Speter  assert(relpath != NULL); /* Driver error */
858251881Speter
859251881Speter  SVN_ERR(fb->processor->file_closed(relpath,
860251881Speter                                     left_source,
861251881Speter                                     right_source,
862251881Speter                                     file_baton,
863251881Speter                                     fb->processor,
864251881Speter                                     scratch_pool));
865251881Speter
866251881Speter  return SVN_NO_ERROR;
867251881Speter}
868251881Speter
869251881Speterstatic svn_error_t *
870251881Speterfilter_node_absent(const char *relpath,
871251881Speter                   void *dir_baton,
872251881Speter                   const svn_diff_tree_processor_t *processor,
873251881Speter                   apr_pool_t *scratch_pool)
874251881Speter{
875251881Speter  struct filter_tree_baton_t *fb = processor->baton;
876251881Speter
877251881Speter  relpath = svn_relpath_skip_ancestor(fb->prefix_relpath, relpath);
878251881Speter  assert(relpath != NULL); /* Driver error */
879251881Speter
880251881Speter  SVN_ERR(fb->processor->node_absent(relpath,
881251881Speter                                    dir_baton,
882251881Speter                                    fb->processor,
883251881Speter                                    scratch_pool));
884251881Speter  return SVN_NO_ERROR;
885251881Speter}
886251881Speter
887251881Speter
888251881Speterconst svn_diff_tree_processor_t *
889251881Spetersvn_diff__tree_processor_filter_create(const svn_diff_tree_processor_t * processor,
890251881Speter                                        const char *prefix_relpath,
891251881Speter                                        apr_pool_t *result_pool)
892251881Speter{
893251881Speter  struct filter_tree_baton_t *fb;
894251881Speter  svn_diff_tree_processor_t *filter;
895251881Speter
896251881Speter  fb = apr_pcalloc(result_pool, sizeof(*fb));
897251881Speter  fb->processor = processor;
898251881Speter  if (prefix_relpath)
899251881Speter    fb->prefix_relpath = apr_pstrdup(result_pool, prefix_relpath);
900251881Speter
901251881Speter  filter = svn_diff__tree_processor_create(fb, result_pool);
902251881Speter
903251881Speter  filter->dir_opened   = filter_dir_opened;
904251881Speter  filter->dir_added    = filter_dir_added;
905251881Speter  filter->dir_deleted  = filter_dir_deleted;
906251881Speter  filter->dir_changed  = filter_dir_changed;
907251881Speter  filter->dir_closed   = filter_dir_closed;
908251881Speter
909251881Speter  filter->file_opened   = filter_file_opened;
910251881Speter  filter->file_added    = filter_file_added;
911251881Speter  filter->file_deleted  = filter_file_deleted;
912251881Speter  filter->file_changed  = filter_file_changed;
913251881Speter  filter->file_closed   = filter_file_closed;
914251881Speter
915251881Speter  filter->node_absent   = filter_node_absent;
916251881Speter
917251881Speter  return filter;
918251881Speter}
919251881Speter
920251881Speterstruct copy_as_changed_baton_t
921251881Speter{
922251881Speter  const svn_diff_tree_processor_t *processor;
923251881Speter};
924251881Speter
925251881Speterstatic svn_error_t *
926251881Spetercopy_as_changed_dir_opened(void **new_dir_baton,
927251881Speter                           svn_boolean_t *skip,
928251881Speter                           svn_boolean_t *skip_children,
929251881Speter                           const char *relpath,
930251881Speter                           const svn_diff_source_t *left_source,
931251881Speter                           const svn_diff_source_t *right_source,
932251881Speter                           const svn_diff_source_t *copyfrom_source,
933251881Speter                           void *parent_dir_baton,
934251881Speter                           const svn_diff_tree_processor_t *processor,
935251881Speter                           apr_pool_t *result_pool,
936251881Speter                           apr_pool_t *scratch_pool)
937251881Speter{
938251881Speter  struct copy_as_changed_baton_t *cb = processor->baton;
939251881Speter
940251881Speter  if (!left_source && copyfrom_source)
941251881Speter    {
942251881Speter      assert(right_source != NULL);
943251881Speter
944251881Speter      left_source = copyfrom_source;
945251881Speter      copyfrom_source = NULL;
946251881Speter    }
947251881Speter
948251881Speter  SVN_ERR(cb->processor->dir_opened(new_dir_baton, skip, skip_children,
949251881Speter                                    relpath,
950251881Speter                                    left_source, right_source,
951251881Speter                                    copyfrom_source,
952251881Speter                                    parent_dir_baton,
953251881Speter                                    cb->processor,
954251881Speter                                    result_pool, scratch_pool));
955251881Speter  return SVN_NO_ERROR;
956251881Speter}
957251881Speter
958251881Speterstatic svn_error_t *
959251881Spetercopy_as_changed_dir_added(const char *relpath,
960251881Speter                          const svn_diff_source_t *copyfrom_source,
961251881Speter                          const svn_diff_source_t *right_source,
962251881Speter                          /*const*/ apr_hash_t *copyfrom_props,
963251881Speter                          /*const*/ apr_hash_t *right_props,
964251881Speter                          void *dir_baton,
965251881Speter                          const svn_diff_tree_processor_t *processor,
966251881Speter                          apr_pool_t *scratch_pool)
967251881Speter{
968251881Speter  struct copy_as_changed_baton_t *cb = processor->baton;
969251881Speter
970251881Speter  if (copyfrom_source)
971251881Speter    {
972251881Speter      apr_array_header_t *propchanges;
973251881Speter      SVN_ERR(svn_prop_diffs(&propchanges, right_props, copyfrom_props,
974251881Speter                             scratch_pool));
975251881Speter      SVN_ERR(cb->processor->dir_changed(relpath,
976251881Speter                                         copyfrom_source,
977251881Speter                                         right_source,
978251881Speter                                         copyfrom_props,
979251881Speter                                         right_props,
980251881Speter                                         propchanges,
981251881Speter                                         dir_baton,
982251881Speter                                         cb->processor,
983251881Speter                                         scratch_pool));
984251881Speter    }
985251881Speter  else
986251881Speter    {
987251881Speter      SVN_ERR(cb->processor->dir_added(relpath,
988251881Speter                                       copyfrom_source,
989251881Speter                                       right_source,
990251881Speter                                       copyfrom_props,
991251881Speter                                       right_props,
992251881Speter                                       dir_baton,
993251881Speter                                       cb->processor,
994251881Speter                                       scratch_pool));
995251881Speter    }
996251881Speter
997251881Speter  return SVN_NO_ERROR;
998251881Speter}
999251881Speter
1000251881Speterstatic svn_error_t *
1001251881Spetercopy_as_changed_dir_deleted(const char *relpath,
1002251881Speter                            const svn_diff_source_t *left_source,
1003251881Speter                            /*const*/ apr_hash_t *left_props,
1004251881Speter                            void *dir_baton,
1005251881Speter                            const svn_diff_tree_processor_t *processor,
1006251881Speter                            apr_pool_t *scratch_pool)
1007251881Speter{
1008251881Speter  struct copy_as_changed_baton_t *cb = processor->baton;
1009251881Speter
1010251881Speter  SVN_ERR(cb->processor->dir_deleted(relpath,
1011251881Speter                                     left_source,
1012251881Speter                                     left_props,
1013251881Speter                                     dir_baton,
1014251881Speter                                     cb->processor,
1015251881Speter                                     scratch_pool));
1016251881Speter
1017251881Speter  return SVN_NO_ERROR;
1018251881Speter}
1019251881Speter
1020251881Speterstatic svn_error_t *
1021251881Spetercopy_as_changed_dir_changed(const char *relpath,
1022251881Speter                            const svn_diff_source_t *left_source,
1023251881Speter                            const svn_diff_source_t *right_source,
1024251881Speter                            /*const*/ apr_hash_t *left_props,
1025251881Speter                            /*const*/ apr_hash_t *right_props,
1026251881Speter                            const apr_array_header_t *prop_changes,
1027251881Speter                            void *dir_baton,
1028251881Speter                            const struct svn_diff_tree_processor_t *processor,
1029251881Speter                            apr_pool_t *scratch_pool)
1030251881Speter{
1031251881Speter  struct copy_as_changed_baton_t *cb = processor->baton;
1032251881Speter
1033251881Speter  SVN_ERR(cb->processor->dir_changed(relpath,
1034251881Speter                                     left_source,
1035251881Speter                                     right_source,
1036251881Speter                                     left_props,
1037251881Speter                                     right_props,
1038251881Speter                                     prop_changes,
1039251881Speter                                     dir_baton,
1040251881Speter                                     cb->processor,
1041251881Speter                                     scratch_pool));
1042251881Speter  return SVN_NO_ERROR;
1043251881Speter}
1044251881Speter
1045251881Speterstatic svn_error_t *
1046251881Spetercopy_as_changed_dir_closed(const char *relpath,
1047251881Speter                           const svn_diff_source_t *left_source,
1048251881Speter                           const svn_diff_source_t *right_source,
1049251881Speter                           void *dir_baton,
1050251881Speter                           const svn_diff_tree_processor_t *processor,
1051251881Speter                           apr_pool_t *scratch_pool)
1052251881Speter{
1053251881Speter  struct copy_as_changed_baton_t *cb = processor->baton;
1054251881Speter
1055251881Speter  SVN_ERR(cb->processor->dir_closed(relpath,
1056251881Speter                                    left_source,
1057251881Speter                                    right_source,
1058251881Speter                                    dir_baton,
1059251881Speter                                    cb->processor,
1060251881Speter                                    scratch_pool));
1061251881Speter  return SVN_NO_ERROR;
1062251881Speter}
1063251881Speter
1064251881Speterstatic svn_error_t *
1065251881Spetercopy_as_changed_file_opened(void **new_file_baton,
1066251881Speter                            svn_boolean_t *skip,
1067251881Speter                            const char *relpath,
1068251881Speter                            const svn_diff_source_t *left_source,
1069251881Speter                            const svn_diff_source_t *right_source,
1070251881Speter                            const svn_diff_source_t *copyfrom_source,
1071251881Speter                            void *dir_baton,
1072251881Speter                            const svn_diff_tree_processor_t *processor,
1073251881Speter                            apr_pool_t *result_pool,
1074251881Speter                            apr_pool_t *scratch_pool)
1075251881Speter{
1076251881Speter  struct copy_as_changed_baton_t *cb = processor->baton;
1077251881Speter
1078251881Speter  if (!left_source && copyfrom_source)
1079251881Speter    {
1080251881Speter      assert(right_source != NULL);
1081251881Speter
1082251881Speter      left_source = copyfrom_source;
1083251881Speter      copyfrom_source = NULL;
1084251881Speter    }
1085251881Speter
1086251881Speter  SVN_ERR(cb->processor->file_opened(new_file_baton,
1087251881Speter                                     skip,
1088251881Speter                                     relpath,
1089251881Speter                                     left_source,
1090251881Speter                                     right_source,
1091251881Speter                                     copyfrom_source,
1092251881Speter                                     dir_baton,
1093251881Speter                                     cb->processor,
1094251881Speter                                     result_pool,
1095251881Speter                                     scratch_pool));
1096251881Speter  return SVN_NO_ERROR;
1097251881Speter}
1098251881Speter
1099251881Speterstatic svn_error_t *
1100251881Spetercopy_as_changed_file_added(const char *relpath,
1101251881Speter                           const svn_diff_source_t *copyfrom_source,
1102251881Speter                           const svn_diff_source_t *right_source,
1103251881Speter                           const char *copyfrom_file,
1104251881Speter                           const char *right_file,
1105251881Speter                           /*const*/ apr_hash_t *copyfrom_props,
1106251881Speter                           /*const*/ apr_hash_t *right_props,
1107251881Speter                           void *file_baton,
1108251881Speter                           const svn_diff_tree_processor_t *processor,
1109251881Speter                           apr_pool_t *scratch_pool)
1110251881Speter{
1111251881Speter  struct copy_as_changed_baton_t *cb = processor->baton;
1112251881Speter
1113251881Speter  if (copyfrom_source)
1114251881Speter    {
1115251881Speter      apr_array_header_t *propchanges;
1116251881Speter      svn_boolean_t same;
1117251881Speter      SVN_ERR(svn_prop_diffs(&propchanges, right_props, copyfrom_props,
1118251881Speter                             scratch_pool));
1119251881Speter
1120251881Speter      /* "" is sometimes a marker for just modified (E.g. no-textdeltas),
1121251881Speter         and it is certainly not a file */
1122251881Speter      if (*copyfrom_file && *right_file)
1123251881Speter        {
1124251881Speter          SVN_ERR(svn_io_files_contents_same_p(&same, copyfrom_file,
1125251881Speter                                               right_file, scratch_pool));
1126251881Speter        }
1127251881Speter      else
1128251881Speter        same = FALSE;
1129251881Speter
1130251881Speter      SVN_ERR(cb->processor->file_changed(relpath,
1131251881Speter                                          copyfrom_source,
1132251881Speter                                          right_source,
1133251881Speter                                          copyfrom_file,
1134251881Speter                                          right_file,
1135251881Speter                                          copyfrom_props,
1136251881Speter                                          right_props,
1137251881Speter                                          !same,
1138251881Speter                                          propchanges,
1139251881Speter                                          file_baton,
1140251881Speter                                          cb->processor,
1141251881Speter                                          scratch_pool));
1142251881Speter    }
1143251881Speter  else
1144251881Speter    {
1145251881Speter      SVN_ERR(cb->processor->file_added(relpath,
1146251881Speter                                        copyfrom_source,
1147251881Speter                                        right_source,
1148251881Speter                                        copyfrom_file,
1149251881Speter                                        right_file,
1150251881Speter                                        copyfrom_props,
1151251881Speter                                        right_props,
1152251881Speter                                        file_baton,
1153251881Speter                                        cb->processor,
1154251881Speter                                        scratch_pool));
1155251881Speter    }
1156251881Speter  return SVN_NO_ERROR;
1157251881Speter}
1158251881Speter
1159251881Speterstatic svn_error_t *
1160251881Spetercopy_as_changed_file_deleted(const char *relpath,
1161251881Speter                             const svn_diff_source_t *left_source,
1162251881Speter                             const char *left_file,
1163251881Speter                             /*const*/ apr_hash_t *left_props,
1164251881Speter                             void *file_baton,
1165251881Speter                             const svn_diff_tree_processor_t *processor,
1166251881Speter                             apr_pool_t *scratch_pool)
1167251881Speter{
1168251881Speter  struct copy_as_changed_baton_t *cb = processor->baton;
1169251881Speter
1170251881Speter  SVN_ERR(cb->processor->file_deleted(relpath,
1171251881Speter                                      left_source,
1172251881Speter                                      left_file,
1173251881Speter                                      left_props,
1174251881Speter                                      file_baton,
1175251881Speter                                      cb->processor,
1176251881Speter                                      scratch_pool));
1177251881Speter
1178251881Speter  return SVN_NO_ERROR;
1179251881Speter}
1180251881Speter
1181251881Speterstatic svn_error_t *
1182251881Spetercopy_as_changed_file_changed(const char *relpath,
1183251881Speter                             const svn_diff_source_t *left_source,
1184251881Speter                             const svn_diff_source_t *right_source,
1185251881Speter                             const char *left_file,
1186251881Speter                             const char *right_file,
1187251881Speter                             /*const*/ apr_hash_t *left_props,
1188251881Speter                             /*const*/ apr_hash_t *right_props,
1189251881Speter                             svn_boolean_t file_modified,
1190251881Speter                             const apr_array_header_t *prop_changes,
1191251881Speter                             void *file_baton,
1192251881Speter                             const svn_diff_tree_processor_t *processor,
1193251881Speter                             apr_pool_t *scratch_pool)
1194251881Speter{
1195251881Speter  struct copy_as_changed_baton_t *cb = processor->baton;
1196251881Speter
1197251881Speter  SVN_ERR(cb->processor->file_changed(relpath,
1198251881Speter                                      left_source,
1199251881Speter                                      right_source,
1200251881Speter                                      left_file,
1201251881Speter                                      right_file,
1202251881Speter                                      left_props,
1203251881Speter                                      right_props,
1204251881Speter                                      file_modified,
1205251881Speter                                      prop_changes,
1206251881Speter                                      file_baton,
1207251881Speter                                      cb->processor,
1208251881Speter                                      scratch_pool));
1209251881Speter  return SVN_NO_ERROR;
1210251881Speter}
1211251881Speter
1212251881Speterstatic svn_error_t *
1213251881Spetercopy_as_changed_file_closed(const char *relpath,
1214251881Speter                            const svn_diff_source_t *left_source,
1215251881Speter                            const svn_diff_source_t *right_source,
1216251881Speter                            void *file_baton,
1217251881Speter                            const svn_diff_tree_processor_t *processor,
1218251881Speter                            apr_pool_t *scratch_pool)
1219251881Speter{
1220251881Speter  struct copy_as_changed_baton_t *cb = processor->baton;
1221251881Speter
1222251881Speter  SVN_ERR(cb->processor->file_closed(relpath,
1223251881Speter                                     left_source,
1224251881Speter                                     right_source,
1225251881Speter                                     file_baton,
1226251881Speter                                     cb->processor,
1227251881Speter                                     scratch_pool));
1228251881Speter
1229251881Speter  return SVN_NO_ERROR;
1230251881Speter}
1231251881Speter
1232251881Speterstatic svn_error_t *
1233251881Spetercopy_as_changed_node_absent(const char *relpath,
1234251881Speter                            void *dir_baton,
1235251881Speter                            const svn_diff_tree_processor_t *processor,
1236251881Speter                            apr_pool_t *scratch_pool)
1237251881Speter{
1238251881Speter  struct copy_as_changed_baton_t *cb = processor->baton;
1239251881Speter
1240251881Speter  SVN_ERR(cb->processor->node_absent(relpath,
1241251881Speter                                    dir_baton,
1242251881Speter                                    cb->processor,
1243251881Speter                                    scratch_pool));
1244251881Speter  return SVN_NO_ERROR;
1245251881Speter}
1246251881Speter
1247251881Speter
1248251881Speterconst svn_diff_tree_processor_t *
1249251881Spetersvn_diff__tree_processor_copy_as_changed_create(
1250251881Speter                        const svn_diff_tree_processor_t * processor,
1251251881Speter                        apr_pool_t *result_pool)
1252251881Speter{
1253251881Speter  struct copy_as_changed_baton_t *cb;
1254251881Speter  svn_diff_tree_processor_t *filter;
1255251881Speter
1256251881Speter  cb = apr_pcalloc(result_pool, sizeof(*cb));
1257251881Speter  cb->processor = processor;
1258251881Speter
1259251881Speter  filter = svn_diff__tree_processor_create(cb, result_pool);
1260251881Speter  filter->dir_opened   = copy_as_changed_dir_opened;
1261251881Speter  filter->dir_added    = copy_as_changed_dir_added;
1262251881Speter  filter->dir_deleted  = copy_as_changed_dir_deleted;
1263251881Speter  filter->dir_changed  = copy_as_changed_dir_changed;
1264251881Speter  filter->dir_closed   = copy_as_changed_dir_closed;
1265251881Speter
1266251881Speter  filter->file_opened   = copy_as_changed_file_opened;
1267251881Speter  filter->file_added    = copy_as_changed_file_added;
1268251881Speter  filter->file_deleted  = copy_as_changed_file_deleted;
1269251881Speter  filter->file_changed  = copy_as_changed_file_changed;
1270251881Speter  filter->file_closed   = copy_as_changed_file_closed;
1271251881Speter
1272251881Speter  filter->node_absent   = copy_as_changed_node_absent;
1273251881Speter
1274251881Speter  return filter;
1275251881Speter}
1276251881Speter
1277251881Speter
1278251881Speter/* Processor baton for the tee tree processor */
1279251881Speterstruct tee_baton_t
1280251881Speter{
1281251881Speter  const svn_diff_tree_processor_t *p1;
1282251881Speter  const svn_diff_tree_processor_t *p2;
1283251881Speter};
1284251881Speter
1285251881Speter/* Wrapper baton for file and directory batons in the tee processor */
1286251881Speterstruct tee_node_baton_t
1287251881Speter{
1288251881Speter  void *baton1;
1289251881Speter  void *baton2;
1290251881Speter};
1291251881Speter
1292251881Speterstatic svn_error_t *
1293251881Spetertee_dir_opened(void **new_dir_baton,
1294251881Speter               svn_boolean_t *skip,
1295251881Speter               svn_boolean_t *skip_children,
1296251881Speter               const char *relpath,
1297251881Speter               const svn_diff_source_t *left_source,
1298251881Speter               const svn_diff_source_t *right_source,
1299251881Speter               const svn_diff_source_t *copyfrom_source,
1300251881Speter               void *parent_dir_baton,
1301251881Speter               const svn_diff_tree_processor_t *processor,
1302251881Speter               apr_pool_t *result_pool,
1303251881Speter               apr_pool_t *scratch_pool)
1304251881Speter{
1305251881Speter  struct tee_baton_t *tb = processor->baton;
1306251881Speter  struct tee_node_baton_t *pb = parent_dir_baton;
1307251881Speter  struct tee_node_baton_t *nb = apr_pcalloc(result_pool, sizeof(*nb));
1308251881Speter
1309251881Speter  SVN_ERR(tb->p1->dir_opened(&(nb->baton1),
1310251881Speter                             skip,
1311251881Speter                             skip_children,
1312251881Speter                             relpath,
1313251881Speter                             left_source,
1314251881Speter                             right_source,
1315251881Speter                             copyfrom_source,
1316251881Speter                             pb ? pb->baton1 : NULL,
1317251881Speter                             tb->p1,
1318251881Speter                             result_pool,
1319251881Speter                             scratch_pool));
1320251881Speter
1321251881Speter  SVN_ERR(tb->p2->dir_opened(&(nb->baton2),
1322251881Speter                             skip,
1323251881Speter                             skip_children,
1324251881Speter                             relpath,
1325251881Speter                             left_source,
1326251881Speter                             right_source,
1327251881Speter                             copyfrom_source,
1328251881Speter                             pb ? pb->baton2 : NULL,
1329251881Speter                             tb->p2,
1330251881Speter                             result_pool,
1331251881Speter                             scratch_pool));
1332251881Speter
1333251881Speter  *new_dir_baton = nb;
1334251881Speter
1335251881Speter  return SVN_NO_ERROR;
1336251881Speter}
1337251881Speter
1338251881Speterstatic svn_error_t *
1339251881Spetertee_dir_added(const char *relpath,
1340251881Speter              const svn_diff_source_t *copyfrom_source,
1341251881Speter              const svn_diff_source_t *right_source,
1342251881Speter              /*const*/ apr_hash_t *copyfrom_props,
1343251881Speter              /*const*/ apr_hash_t *right_props,
1344251881Speter              void *dir_baton,
1345251881Speter              const svn_diff_tree_processor_t *processor,
1346251881Speter              apr_pool_t *scratch_pool)
1347251881Speter{
1348251881Speter  struct tee_baton_t *tb = processor->baton;
1349251881Speter  struct tee_node_baton_t *db = dir_baton;
1350251881Speter
1351251881Speter  SVN_ERR(tb->p1->dir_added(relpath,
1352251881Speter                            copyfrom_source,
1353251881Speter                            right_source,
1354251881Speter                            copyfrom_props,
1355251881Speter                            right_props,
1356251881Speter                            db->baton1,
1357251881Speter                            tb->p1,
1358251881Speter                            scratch_pool));
1359251881Speter
1360251881Speter  SVN_ERR(tb->p2->dir_added(relpath,
1361251881Speter                            copyfrom_source,
1362251881Speter                            right_source,
1363251881Speter                            copyfrom_props,
1364251881Speter                            right_props,
1365251881Speter                            db->baton2,
1366251881Speter                            tb->p2,
1367251881Speter                            scratch_pool));
1368251881Speter
1369251881Speter  return SVN_NO_ERROR;
1370251881Speter}
1371251881Speter
1372251881Speterstatic svn_error_t *
1373251881Spetertee_dir_deleted(const char *relpath,
1374251881Speter                const svn_diff_source_t *left_source,
1375251881Speter                /*const*/ apr_hash_t *left_props,
1376251881Speter                void *dir_baton,
1377251881Speter                const svn_diff_tree_processor_t *processor,
1378251881Speter                apr_pool_t *scratch_pool)
1379251881Speter{
1380251881Speter  struct tee_baton_t *tb = processor->baton;
1381251881Speter  struct tee_node_baton_t *db = dir_baton;
1382251881Speter
1383251881Speter  SVN_ERR(tb->p1->dir_deleted(relpath,
1384251881Speter                              left_source,
1385251881Speter                              left_props,
1386251881Speter                              db->baton1,
1387251881Speter                              tb->p1,
1388251881Speter                              scratch_pool));
1389251881Speter
1390251881Speter  SVN_ERR(tb->p2->dir_deleted(relpath,
1391251881Speter                              left_source,
1392251881Speter                              left_props,
1393251881Speter                              db->baton2,
1394251881Speter                              tb->p2,
1395251881Speter                              scratch_pool));
1396251881Speter
1397251881Speter  return SVN_NO_ERROR;
1398251881Speter}
1399251881Speter
1400251881Speterstatic svn_error_t *
1401251881Spetertee_dir_changed(const char *relpath,
1402251881Speter                    const svn_diff_source_t *left_source,
1403251881Speter                    const svn_diff_source_t *right_source,
1404251881Speter                    /*const*/ apr_hash_t *left_props,
1405251881Speter                    /*const*/ apr_hash_t *right_props,
1406251881Speter                    const apr_array_header_t *prop_changes,
1407251881Speter                    void *dir_baton,
1408251881Speter                    const struct svn_diff_tree_processor_t *processor,
1409251881Speter                    apr_pool_t *scratch_pool)
1410251881Speter{
1411251881Speter  struct tee_baton_t *tb = processor->baton;
1412251881Speter  struct tee_node_baton_t *db = dir_baton;
1413251881Speter
1414251881Speter  SVN_ERR(tb->p1->dir_changed(relpath,
1415251881Speter                              left_source,
1416251881Speter                              right_source,
1417251881Speter                              left_props,
1418251881Speter                              right_props,
1419251881Speter                              prop_changes,
1420251881Speter                              db->baton1,
1421251881Speter                              tb->p1,
1422251881Speter                              scratch_pool));
1423251881Speter
1424251881Speter  SVN_ERR(tb->p2->dir_changed(relpath,
1425251881Speter                              left_source,
1426251881Speter                              right_source,
1427251881Speter                              left_props,
1428251881Speter                              right_props,
1429251881Speter                              prop_changes,
1430251881Speter                              db->baton2,
1431251881Speter                              tb->p2,
1432251881Speter                              scratch_pool));
1433251881Speter  return SVN_NO_ERROR;
1434251881Speter}
1435251881Speter
1436251881Speterstatic svn_error_t *
1437251881Spetertee_dir_closed(const char *relpath,
1438251881Speter               const svn_diff_source_t *left_source,
1439251881Speter               const svn_diff_source_t *right_source,
1440251881Speter               void *dir_baton,
1441251881Speter               const svn_diff_tree_processor_t *processor,
1442251881Speter               apr_pool_t *scratch_pool)
1443251881Speter{
1444251881Speter  struct tee_baton_t *tb = processor->baton;
1445251881Speter  struct tee_node_baton_t *db = dir_baton;
1446251881Speter
1447251881Speter  SVN_ERR(tb->p1->dir_closed(relpath,
1448251881Speter                             left_source,
1449251881Speter                             right_source,
1450251881Speter                             db->baton1,
1451251881Speter                             tb->p1,
1452251881Speter                             scratch_pool));
1453251881Speter
1454251881Speter  SVN_ERR(tb->p2->dir_closed(relpath,
1455251881Speter                             left_source,
1456251881Speter                             right_source,
1457251881Speter                             db->baton2,
1458251881Speter                             tb->p2,
1459251881Speter                             scratch_pool));
1460251881Speter  return SVN_NO_ERROR;
1461251881Speter}
1462251881Speter
1463251881Speterstatic svn_error_t *
1464251881Spetertee_file_opened(void **new_file_baton,
1465251881Speter                svn_boolean_t *skip,
1466251881Speter                const char *relpath,
1467251881Speter                const svn_diff_source_t *left_source,
1468251881Speter                const svn_diff_source_t *right_source,
1469251881Speter                const svn_diff_source_t *copyfrom_source,
1470251881Speter                void *dir_baton,
1471251881Speter                const svn_diff_tree_processor_t *processor,
1472251881Speter                apr_pool_t *result_pool,
1473251881Speter                apr_pool_t *scratch_pool)
1474251881Speter{
1475251881Speter  struct tee_baton_t *tb = processor->baton;
1476251881Speter  struct tee_node_baton_t *pb = dir_baton;
1477251881Speter  struct tee_node_baton_t *nb = apr_pcalloc(result_pool, sizeof(*nb));
1478251881Speter
1479251881Speter  SVN_ERR(tb->p1->file_opened(&(nb->baton1),
1480251881Speter                              skip,
1481251881Speter                              relpath,
1482251881Speter                              left_source,
1483251881Speter                              right_source,
1484251881Speter                              copyfrom_source,
1485251881Speter                              pb ? pb->baton1 : NULL,
1486251881Speter                              tb->p1,
1487251881Speter                              result_pool,
1488251881Speter                              scratch_pool));
1489251881Speter
1490251881Speter  SVN_ERR(tb->p2->file_opened(&(nb->baton2),
1491251881Speter                              skip,
1492251881Speter                              relpath,
1493251881Speter                              left_source,
1494251881Speter                              right_source,
1495251881Speter                              copyfrom_source,
1496251881Speter                              pb ? pb->baton2 : NULL,
1497251881Speter                              tb->p2,
1498251881Speter                              result_pool,
1499251881Speter                              scratch_pool));
1500251881Speter
1501251881Speter  *new_file_baton = nb;
1502251881Speter
1503251881Speter  return SVN_NO_ERROR;
1504251881Speter}
1505251881Speter
1506251881Speterstatic svn_error_t *
1507251881Spetertee_file_added(const char *relpath,
1508251881Speter               const svn_diff_source_t *copyfrom_source,
1509251881Speter               const svn_diff_source_t *right_source,
1510251881Speter               const char *copyfrom_file,
1511251881Speter               const char *right_file,
1512251881Speter               /*const*/ apr_hash_t *copyfrom_props,
1513251881Speter               /*const*/ apr_hash_t *right_props,
1514251881Speter               void *file_baton,
1515251881Speter               const svn_diff_tree_processor_t *processor,
1516251881Speter               apr_pool_t *scratch_pool)
1517251881Speter{
1518251881Speter  struct tee_baton_t *tb = processor->baton;
1519251881Speter  struct tee_node_baton_t *fb = file_baton;
1520251881Speter
1521251881Speter  SVN_ERR(tb->p1->file_added(relpath,
1522251881Speter                             copyfrom_source,
1523251881Speter                             right_source,
1524251881Speter                             copyfrom_file,
1525251881Speter                             right_file,
1526251881Speter                             copyfrom_props,
1527251881Speter                             right_props,
1528251881Speter                             fb->baton1,
1529251881Speter                             tb->p1,
1530251881Speter                             scratch_pool));
1531251881Speter
1532251881Speter  SVN_ERR(tb->p2->file_added(relpath,
1533251881Speter                             copyfrom_source,
1534251881Speter                             right_source,
1535251881Speter                             copyfrom_file,
1536251881Speter                             right_file,
1537251881Speter                             copyfrom_props,
1538251881Speter                             right_props,
1539251881Speter                             fb->baton2,
1540251881Speter                             tb->p2,
1541251881Speter                             scratch_pool));
1542251881Speter  return SVN_NO_ERROR;
1543251881Speter}
1544251881Speter
1545251881Speterstatic svn_error_t *
1546251881Spetertee_file_deleted(const char *relpath,
1547251881Speter                 const svn_diff_source_t *left_source,
1548251881Speter                 const char *left_file,
1549251881Speter                 /*const*/ apr_hash_t *left_props,
1550251881Speter                 void *file_baton,
1551251881Speter                 const svn_diff_tree_processor_t *processor,
1552251881Speter                 apr_pool_t *scratch_pool)
1553251881Speter{
1554251881Speter  struct tee_baton_t *tb = processor->baton;
1555251881Speter  struct tee_node_baton_t *fb = file_baton;
1556251881Speter
1557251881Speter  SVN_ERR(tb->p1->file_deleted(relpath,
1558251881Speter                               left_source,
1559251881Speter                               left_file,
1560251881Speter                               left_props,
1561251881Speter                               fb->baton1,
1562251881Speter                               tb->p1,
1563251881Speter                               scratch_pool));
1564251881Speter
1565251881Speter  SVN_ERR(tb->p2->file_deleted(relpath,
1566251881Speter                               left_source,
1567251881Speter                               left_file,
1568251881Speter                               left_props,
1569251881Speter                               fb->baton2,
1570251881Speter                               tb->p2,
1571251881Speter                               scratch_pool));
1572251881Speter  return SVN_NO_ERROR;
1573251881Speter}
1574251881Speter
1575251881Speterstatic svn_error_t *
1576251881Spetertee_file_changed(const char *relpath,
1577251881Speter                 const svn_diff_source_t *left_source,
1578251881Speter                 const svn_diff_source_t *right_source,
1579251881Speter                 const char *left_file,
1580251881Speter                 const char *right_file,
1581251881Speter                 /*const*/ apr_hash_t *left_props,
1582251881Speter                 /*const*/ apr_hash_t *right_props,
1583251881Speter                 svn_boolean_t file_modified,
1584251881Speter                 const apr_array_header_t *prop_changes,
1585251881Speter                 void *file_baton,
1586251881Speter                 const svn_diff_tree_processor_t *processor,
1587251881Speter                 apr_pool_t *scratch_pool)
1588251881Speter{
1589251881Speter  struct tee_baton_t *tb = processor->baton;
1590251881Speter  struct tee_node_baton_t *fb = file_baton;
1591251881Speter
1592251881Speter  SVN_ERR(tb->p1->file_changed(relpath,
1593251881Speter                               left_source,
1594251881Speter                               right_source,
1595251881Speter                               left_file,
1596251881Speter                               right_file,
1597251881Speter                               left_props,
1598251881Speter                               right_props,
1599251881Speter                               file_modified,
1600251881Speter                               prop_changes,
1601251881Speter                               fb->baton1,
1602251881Speter                               tb->p1,
1603251881Speter                               scratch_pool));
1604251881Speter
1605251881Speter  SVN_ERR(tb->p2->file_changed(relpath,
1606251881Speter                               left_source,
1607251881Speter                               right_source,
1608251881Speter                               left_file,
1609251881Speter                               right_file,
1610251881Speter                               left_props,
1611251881Speter                               right_props,
1612251881Speter                               file_modified,
1613251881Speter                               prop_changes,
1614251881Speter                               fb->baton2,
1615251881Speter                               tb->p2,
1616251881Speter                               scratch_pool));
1617251881Speter  return SVN_NO_ERROR;
1618251881Speter}
1619251881Speter
1620251881Speterstatic svn_error_t *
1621251881Spetertee_file_closed(const char *relpath,
1622251881Speter                    const svn_diff_source_t *left_source,
1623251881Speter                    const svn_diff_source_t *right_source,
1624251881Speter                    void *file_baton,
1625251881Speter                    const svn_diff_tree_processor_t *processor,
1626251881Speter                    apr_pool_t *scratch_pool)
1627251881Speter{
1628251881Speter  struct tee_baton_t *tb = processor->baton;
1629251881Speter  struct tee_node_baton_t *fb = file_baton;
1630251881Speter
1631251881Speter  SVN_ERR(tb->p1->file_closed(relpath,
1632251881Speter                              left_source,
1633251881Speter                              right_source,
1634251881Speter                              fb->baton1,
1635251881Speter                              tb->p1,
1636251881Speter                              scratch_pool));
1637251881Speter
1638251881Speter  SVN_ERR(tb->p2->file_closed(relpath,
1639251881Speter                              left_source,
1640251881Speter                              right_source,
1641251881Speter                              fb->baton2,
1642251881Speter                              tb->p2,
1643251881Speter                              scratch_pool));
1644251881Speter
1645251881Speter  return SVN_NO_ERROR;
1646251881Speter}
1647251881Speter
1648251881Speterstatic svn_error_t *
1649251881Spetertee_node_absent(const char *relpath,
1650251881Speter                void *dir_baton,
1651251881Speter                const svn_diff_tree_processor_t *processor,
1652251881Speter                apr_pool_t *scratch_pool)
1653251881Speter{
1654251881Speter  struct tee_baton_t *tb = processor->baton;
1655251881Speter  struct tee_node_baton_t *db = dir_baton;
1656251881Speter
1657251881Speter  SVN_ERR(tb->p1->node_absent(relpath,
1658251881Speter                              db ? db->baton1 : NULL,
1659251881Speter                              tb->p1,
1660251881Speter                              scratch_pool));
1661251881Speter
1662251881Speter  SVN_ERR(tb->p2->node_absent(relpath,
1663251881Speter                              db ? db->baton2 : NULL,
1664251881Speter                              tb->p2,
1665251881Speter                              scratch_pool));
1666251881Speter
1667251881Speter  return SVN_NO_ERROR;
1668251881Speter}
1669251881Speter
1670251881Speterconst svn_diff_tree_processor_t *
1671251881Spetersvn_diff__tree_processor_tee_create(const svn_diff_tree_processor_t *processor1,
1672251881Speter                                    const svn_diff_tree_processor_t *processor2,
1673251881Speter                                    apr_pool_t *result_pool)
1674251881Speter{
1675251881Speter  struct tee_baton_t *tb = apr_pcalloc(result_pool, sizeof(*tb));
1676251881Speter  svn_diff_tree_processor_t *tee;
1677251881Speter  tb->p1 = processor1;
1678251881Speter  tb->p2 = processor2;
1679251881Speter
1680251881Speter  tee = svn_diff__tree_processor_create(tb, result_pool);
1681251881Speter
1682251881Speter  tee->dir_opened    = tee_dir_opened;
1683251881Speter  tee->dir_added     = tee_dir_added;
1684251881Speter  tee->dir_deleted   = tee_dir_deleted;
1685251881Speter  tee->dir_changed   = tee_dir_changed;
1686251881Speter  tee->dir_closed    = tee_dir_closed;
1687251881Speter  tee->file_opened   = tee_file_opened;
1688251881Speter  tee->file_added    = tee_file_added;
1689251881Speter  tee->file_deleted  = tee_file_deleted;
1690251881Speter  tee->file_changed  = tee_file_changed;
1691251881Speter  tee->file_closed   = tee_file_closed;
1692251881Speter  tee->node_absent   = tee_node_absent;
1693251881Speter
1694251881Speter  return tee;
1695251881Speter}
1696251881Speter
1697251881Spetersvn_diff_source_t *
1698251881Spetersvn_diff__source_create(svn_revnum_t revision,
1699251881Speter                        apr_pool_t *result_pool)
1700251881Speter{
1701251881Speter  svn_diff_source_t *src = apr_pcalloc(result_pool, sizeof(*src));
1702251881Speter
1703251881Speter  src->revision = revision;
1704251881Speter  return src;
1705251881Speter}
1706