2 * diff_tree.c : default diff tree processor
4 * ====================================================================
5 * Licensed to the Apache Software Foundation (ASF) under one
6 * or more contributor license agreements. See the NOTICE file
7 * distributed with this work for additional information
8 * regarding copyright ownership. The ASF licenses this file
9 * to you under the Apache License, Version 2.0 (the
10 * "License"); you may not use this file except in compliance
11 * with the License. You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing,
16 * software distributed under the License is distributed on an
17 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18 * KIND, either express or implied. See the License for the
19 * specific language governing permissions and limitations
21 * ====================================================================
25 #include <apr_pools.h>
26 #include <apr_general.h>
30 #include "svn_dirent_uri.h"
31 #include "svn_error.h"
33 #include "svn_pools.h"
34 #include "svn_props.h"
35 #include "svn_types.h"
37 #include "private/svn_diff_tree.h"
38 #include "svn_private_config.h"
40 typedef struct tree_processor_t
42 svn_diff_tree_processor_t tp;
44 /* void *future_extension */
49 default_dir_opened(void **new_dir_baton,
51 svn_boolean_t *skip_children,
53 const svn_diff_source_t *left_source,
54 const svn_diff_source_t *right_source,
55 const svn_diff_source_t *copyfrom_source,
56 void *parent_dir_baton,
57 const svn_diff_tree_processor_t *processor,
58 apr_pool_t *result_pool,
59 apr_pool_t *scratch_pool)
61 *new_dir_baton = NULL;
66 default_dir_added(const char *relpath,
67 const svn_diff_source_t *copyfrom_source,
68 const svn_diff_source_t *right_source,
69 /*const*/ apr_hash_t *copyfrom_props,
70 /*const*/ apr_hash_t *right_props,
72 const svn_diff_tree_processor_t *processor,
73 apr_pool_t *scratch_pool)
75 SVN_ERR(processor->dir_closed(relpath, NULL, right_source,
83 default_dir_deleted(const char *relpath,
84 const svn_diff_source_t *left_source,
85 /*const*/ apr_hash_t *left_props,
87 const svn_diff_tree_processor_t *processor,
88 apr_pool_t *scratch_pool)
90 SVN_ERR(processor->dir_closed(relpath, left_source, NULL,
97 default_dir_changed(const char *relpath,
98 const svn_diff_source_t *left_source,
99 const svn_diff_source_t *right_source,
100 /*const*/ apr_hash_t *left_props,
101 /*const*/ apr_hash_t *right_props,
102 const apr_array_header_t *prop_changes,
104 const struct svn_diff_tree_processor_t *processor,
105 apr_pool_t *scratch_pool)
107 SVN_ERR(processor->dir_closed(relpath,
108 left_source, right_source,
110 processor, scratch_pool));
115 default_dir_closed(const char *relpath,
116 const svn_diff_source_t *left_source,
117 const svn_diff_source_t *right_source,
119 const svn_diff_tree_processor_t *processor,
120 apr_pool_t *scratch_pool)
126 default_file_opened(void **new_file_baton,
129 const svn_diff_source_t *left_source,
130 const svn_diff_source_t *right_source,
131 const svn_diff_source_t *copyfrom_source,
133 const svn_diff_tree_processor_t *processor,
134 apr_pool_t *result_pool,
135 apr_pool_t *scratch_pool)
137 *new_file_baton = dir_baton;
142 default_file_added(const char *relpath,
143 const svn_diff_source_t *copyfrom_source,
144 const svn_diff_source_t *right_source,
145 const char *copyfrom_file,
146 const char *right_file,
147 /*const*/ apr_hash_t *copyfrom_props,
148 /*const*/ apr_hash_t *right_props,
150 const svn_diff_tree_processor_t *processor,
151 apr_pool_t *scratch_pool)
153 SVN_ERR(processor->file_closed(relpath,
155 file_baton, processor, scratch_pool));
160 default_file_deleted(const char *relpath,
161 const svn_diff_source_t *left_source,
162 const char *left_file,
163 /*const*/ apr_hash_t *left_props,
165 const svn_diff_tree_processor_t *processor,
166 apr_pool_t *scratch_pool)
168 SVN_ERR(processor->file_closed(relpath,
170 file_baton, processor, scratch_pool));
175 default_file_changed(const char *relpath,
176 const svn_diff_source_t *left_source,
177 const svn_diff_source_t *right_source,
178 const char *left_file,
179 const char *right_file,
180 /*const*/ apr_hash_t *left_props,
181 /*const*/ apr_hash_t *right_props,
182 svn_boolean_t file_modified,
183 const apr_array_header_t *prop_changes,
185 const svn_diff_tree_processor_t *processor,
186 apr_pool_t *scratch_pool)
188 SVN_ERR(processor->file_closed(relpath,
189 left_source, right_source,
190 file_baton, processor, scratch_pool));
195 default_file_closed(const char *relpath,
196 const svn_diff_source_t *left_source,
197 const svn_diff_source_t *right_source,
199 const svn_diff_tree_processor_t *processor,
200 apr_pool_t *scratch_pool)
206 default_node_absent(const char *relpath,
208 const svn_diff_tree_processor_t *processor,
209 apr_pool_t *scratch_pool)
214 svn_diff_tree_processor_t *
215 svn_diff__tree_processor_create(void *baton,
216 apr_pool_t *result_pool)
218 tree_processor_t *wrapper;
219 wrapper = apr_pcalloc(result_pool, sizeof(*wrapper));
221 wrapper->tp.baton = baton;
223 wrapper->tp.dir_opened = default_dir_opened;
224 wrapper->tp.dir_added = default_dir_added;
225 wrapper->tp.dir_deleted = default_dir_deleted;
226 wrapper->tp.dir_changed = default_dir_changed;
227 wrapper->tp.dir_closed = default_dir_closed;
229 wrapper->tp.file_opened = default_file_opened;
230 wrapper->tp.file_added = default_file_added;
231 wrapper->tp.file_deleted = default_file_deleted;
232 wrapper->tp.file_changed = default_file_changed;
233 wrapper->tp.file_closed = default_file_closed;
235 wrapper->tp.node_absent = default_node_absent;
241 struct reverse_tree_baton_t
243 const svn_diff_tree_processor_t *processor;
244 const char *prefix_relpath;
248 reverse_dir_opened(void **new_dir_baton,
250 svn_boolean_t *skip_children,
252 const svn_diff_source_t *left_source,
253 const svn_diff_source_t *right_source,
254 const svn_diff_source_t *copyfrom_source,
255 void *parent_dir_baton,
256 const svn_diff_tree_processor_t *processor,
257 apr_pool_t *result_pool,
258 apr_pool_t *scratch_pool)
260 struct reverse_tree_baton_t *rb = processor->baton;
262 if (rb->prefix_relpath)
263 relpath = svn_relpath_join(rb->prefix_relpath, relpath, scratch_pool);
265 SVN_ERR(rb->processor->dir_opened(new_dir_baton, skip, skip_children,
267 right_source, left_source,
271 result_pool, scratch_pool));
276 reverse_dir_added(const char *relpath,
277 const svn_diff_source_t *copyfrom_source,
278 const svn_diff_source_t *right_source,
279 /*const*/ apr_hash_t *copyfrom_props,
280 /*const*/ apr_hash_t *right_props,
282 const svn_diff_tree_processor_t *processor,
283 apr_pool_t *scratch_pool)
285 struct reverse_tree_baton_t *rb = processor->baton;
287 if (rb->prefix_relpath)
288 relpath = svn_relpath_join(rb->prefix_relpath, relpath, scratch_pool);
290 SVN_ERR(rb->processor->dir_deleted(relpath,
301 reverse_dir_deleted(const char *relpath,
302 const svn_diff_source_t *left_source,
303 /*const*/ apr_hash_t *left_props,
305 const svn_diff_tree_processor_t *processor,
306 apr_pool_t *scratch_pool)
308 struct reverse_tree_baton_t *rb = processor->baton;
310 if (rb->prefix_relpath)
311 relpath = svn_relpath_join(rb->prefix_relpath, relpath, scratch_pool);
313 SVN_ERR(rb->processor->dir_added(relpath,
325 reverse_dir_changed(const char *relpath,
326 const svn_diff_source_t *left_source,
327 const svn_diff_source_t *right_source,
328 /*const*/ apr_hash_t *left_props,
329 /*const*/ apr_hash_t *right_props,
330 const apr_array_header_t *prop_changes,
332 const struct svn_diff_tree_processor_t *processor,
333 apr_pool_t *scratch_pool)
335 struct reverse_tree_baton_t *rb = processor->baton;
336 apr_array_header_t *reversed_prop_changes = NULL;
338 if (rb->prefix_relpath)
339 relpath = svn_relpath_join(rb->prefix_relpath, relpath, scratch_pool);
343 SVN_ERR_ASSERT(left_props != NULL && right_props != NULL);
344 SVN_ERR(svn_prop_diffs(&reversed_prop_changes, left_props, right_props,
348 SVN_ERR(rb->processor->dir_changed(relpath,
353 reversed_prop_changes,
361 reverse_dir_closed(const char *relpath,
362 const svn_diff_source_t *left_source,
363 const svn_diff_source_t *right_source,
365 const svn_diff_tree_processor_t *processor,
366 apr_pool_t *scratch_pool)
368 struct reverse_tree_baton_t *rb = processor->baton;
370 if (rb->prefix_relpath)
371 relpath = svn_relpath_join(rb->prefix_relpath, relpath, scratch_pool);
373 SVN_ERR(rb->processor->dir_closed(relpath,
383 reverse_file_opened(void **new_file_baton,
386 const svn_diff_source_t *left_source,
387 const svn_diff_source_t *right_source,
388 const svn_diff_source_t *copyfrom_source,
390 const svn_diff_tree_processor_t *processor,
391 apr_pool_t *result_pool,
392 apr_pool_t *scratch_pool)
394 struct reverse_tree_baton_t *rb = processor->baton;
396 if (rb->prefix_relpath)
397 relpath = svn_relpath_join(rb->prefix_relpath, relpath, scratch_pool);
399 SVN_ERR(rb->processor->file_opened(new_file_baton,
404 NULL /* copy_from */,
413 reverse_file_added(const char *relpath,
414 const svn_diff_source_t *copyfrom_source,
415 const svn_diff_source_t *right_source,
416 const char *copyfrom_file,
417 const char *right_file,
418 /*const*/ apr_hash_t *copyfrom_props,
419 /*const*/ apr_hash_t *right_props,
421 const svn_diff_tree_processor_t *processor,
422 apr_pool_t *scratch_pool)
424 struct reverse_tree_baton_t *rb = processor->baton;
426 if (rb->prefix_relpath)
427 relpath = svn_relpath_join(rb->prefix_relpath, relpath, scratch_pool);
429 SVN_ERR(rb->processor->file_deleted(relpath,
440 reverse_file_deleted(const char *relpath,
441 const svn_diff_source_t *left_source,
442 const char *left_file,
443 /*const*/ apr_hash_t *left_props,
445 const svn_diff_tree_processor_t *processor,
446 apr_pool_t *scratch_pool)
448 struct reverse_tree_baton_t *rb = processor->baton;
450 if (rb->prefix_relpath)
451 relpath = svn_relpath_join(rb->prefix_relpath, relpath, scratch_pool);
453 SVN_ERR(rb->processor->file_added(relpath,
454 NULL /* copyfrom src */,
456 NULL /* copyfrom file */,
458 NULL /* copyfrom props */,
467 reverse_file_changed(const char *relpath,
468 const svn_diff_source_t *left_source,
469 const svn_diff_source_t *right_source,
470 const char *left_file,
471 const char *right_file,
472 /*const*/ apr_hash_t *left_props,
473 /*const*/ apr_hash_t *right_props,
474 svn_boolean_t file_modified,
475 const apr_array_header_t *prop_changes,
477 const svn_diff_tree_processor_t *processor,
478 apr_pool_t *scratch_pool)
480 struct reverse_tree_baton_t *rb = processor->baton;
481 apr_array_header_t *reversed_prop_changes = NULL;
483 if (rb->prefix_relpath)
484 relpath = svn_relpath_join(rb->prefix_relpath, relpath, scratch_pool);
488 SVN_ERR_ASSERT(left_props != NULL && right_props != NULL);
489 SVN_ERR(svn_prop_diffs(&reversed_prop_changes, left_props, right_props,
493 SVN_ERR(rb->processor->file_changed(relpath,
501 reversed_prop_changes,
509 reverse_file_closed(const char *relpath,
510 const svn_diff_source_t *left_source,
511 const svn_diff_source_t *right_source,
513 const svn_diff_tree_processor_t *processor,
514 apr_pool_t *scratch_pool)
516 struct reverse_tree_baton_t *rb = processor->baton;
518 if (rb->prefix_relpath)
519 relpath = svn_relpath_join(rb->prefix_relpath, relpath, scratch_pool);
521 SVN_ERR(rb->processor->file_closed(relpath,
532 reverse_node_absent(const char *relpath,
534 const svn_diff_tree_processor_t *processor,
535 apr_pool_t *scratch_pool)
537 struct reverse_tree_baton_t *rb = processor->baton;
539 if (rb->prefix_relpath)
540 relpath = svn_relpath_join(rb->prefix_relpath, relpath, scratch_pool);
542 SVN_ERR(rb->processor->node_absent(relpath,
550 const svn_diff_tree_processor_t *
551 svn_diff__tree_processor_reverse_create(const svn_diff_tree_processor_t * processor,
552 const char *prefix_relpath,
553 apr_pool_t *result_pool)
555 struct reverse_tree_baton_t *rb;
556 svn_diff_tree_processor_t *reverse;
558 rb = apr_pcalloc(result_pool, sizeof(*rb));
559 rb->processor = processor;
561 rb->prefix_relpath = apr_pstrdup(result_pool, prefix_relpath);
563 reverse = svn_diff__tree_processor_create(rb, result_pool);
565 reverse->dir_opened = reverse_dir_opened;
566 reverse->dir_added = reverse_dir_added;
567 reverse->dir_deleted = reverse_dir_deleted;
568 reverse->dir_changed = reverse_dir_changed;
569 reverse->dir_closed = reverse_dir_closed;
571 reverse->file_opened = reverse_file_opened;
572 reverse->file_added = reverse_file_added;
573 reverse->file_deleted = reverse_file_deleted;
574 reverse->file_changed = reverse_file_changed;
575 reverse->file_closed = reverse_file_closed;
577 reverse->node_absent = reverse_node_absent;
582 struct filter_tree_baton_t
584 const svn_diff_tree_processor_t *processor;
585 const char *prefix_relpath;
589 filter_dir_opened(void **new_dir_baton,
591 svn_boolean_t *skip_children,
593 const svn_diff_source_t *left_source,
594 const svn_diff_source_t *right_source,
595 const svn_diff_source_t *copyfrom_source,
596 void *parent_dir_baton,
597 const svn_diff_tree_processor_t *processor,
598 apr_pool_t *result_pool,
599 apr_pool_t *scratch_pool)
601 struct filter_tree_baton_t *fb = processor->baton;
603 relpath = svn_relpath_skip_ancestor(fb->prefix_relpath, relpath);
607 /* Skip work for this, but NOT for DESCENDANTS */
612 SVN_ERR(fb->processor->dir_opened(new_dir_baton, skip, skip_children,
614 left_source, right_source,
618 result_pool, scratch_pool));
623 filter_dir_added(const char *relpath,
624 const svn_diff_source_t *copyfrom_source,
625 const svn_diff_source_t *right_source,
626 /*const*/ apr_hash_t *copyfrom_props,
627 /*const*/ apr_hash_t *right_props,
629 const svn_diff_tree_processor_t *processor,
630 apr_pool_t *scratch_pool)
632 struct filter_tree_baton_t *fb = processor->baton;
634 relpath = svn_relpath_skip_ancestor(fb->prefix_relpath, relpath);
635 assert(relpath != NULL); /* Driver error */
637 SVN_ERR(fb->processor->dir_added(relpath,
650 filter_dir_deleted(const char *relpath,
651 const svn_diff_source_t *left_source,
652 /*const*/ apr_hash_t *left_props,
654 const svn_diff_tree_processor_t *processor,
655 apr_pool_t *scratch_pool)
657 struct filter_tree_baton_t *fb = processor->baton;
659 relpath = svn_relpath_skip_ancestor(fb->prefix_relpath, relpath);
660 assert(relpath != NULL); /* Driver error */
662 SVN_ERR(fb->processor->dir_deleted(relpath,
673 filter_dir_changed(const char *relpath,
674 const svn_diff_source_t *left_source,
675 const svn_diff_source_t *right_source,
676 /*const*/ apr_hash_t *left_props,
677 /*const*/ apr_hash_t *right_props,
678 const apr_array_header_t *prop_changes,
680 const struct svn_diff_tree_processor_t *processor,
681 apr_pool_t *scratch_pool)
683 struct filter_tree_baton_t *fb = processor->baton;
685 relpath = svn_relpath_skip_ancestor(fb->prefix_relpath, relpath);
686 assert(relpath != NULL); /* Driver error */
688 SVN_ERR(fb->processor->dir_changed(relpath,
701 filter_dir_closed(const char *relpath,
702 const svn_diff_source_t *left_source,
703 const svn_diff_source_t *right_source,
705 const svn_diff_tree_processor_t *processor,
706 apr_pool_t *scratch_pool)
708 struct filter_tree_baton_t *fb = processor->baton;
710 relpath = svn_relpath_skip_ancestor(fb->prefix_relpath, relpath);
711 assert(relpath != NULL); /* Driver error */
713 SVN_ERR(fb->processor->dir_closed(relpath,
723 filter_file_opened(void **new_file_baton,
726 const svn_diff_source_t *left_source,
727 const svn_diff_source_t *right_source,
728 const svn_diff_source_t *copyfrom_source,
730 const svn_diff_tree_processor_t *processor,
731 apr_pool_t *result_pool,
732 apr_pool_t *scratch_pool)
734 struct filter_tree_baton_t *fb = processor->baton;
736 relpath = svn_relpath_skip_ancestor(fb->prefix_relpath, relpath);
744 SVN_ERR(fb->processor->file_opened(new_file_baton,
758 filter_file_added(const char *relpath,
759 const svn_diff_source_t *copyfrom_source,
760 const svn_diff_source_t *right_source,
761 const char *copyfrom_file,
762 const char *right_file,
763 /*const*/ apr_hash_t *copyfrom_props,
764 /*const*/ apr_hash_t *right_props,
766 const svn_diff_tree_processor_t *processor,
767 apr_pool_t *scratch_pool)
769 struct filter_tree_baton_t *fb = processor->baton;
771 relpath = svn_relpath_skip_ancestor(fb->prefix_relpath, relpath);
772 assert(relpath != NULL); /* Driver error */
774 SVN_ERR(fb->processor->file_added(relpath,
788 filter_file_deleted(const char *relpath,
789 const svn_diff_source_t *left_source,
790 const char *left_file,
791 /*const*/ apr_hash_t *left_props,
793 const svn_diff_tree_processor_t *processor,
794 apr_pool_t *scratch_pool)
796 struct filter_tree_baton_t *fb = processor->baton;
798 relpath = svn_relpath_skip_ancestor(fb->prefix_relpath, relpath);
799 assert(relpath != NULL); /* Driver error */
801 SVN_ERR(fb->processor->file_deleted(relpath,
813 filter_file_changed(const char *relpath,
814 const svn_diff_source_t *left_source,
815 const svn_diff_source_t *right_source,
816 const char *left_file,
817 const char *right_file,
818 /*const*/ apr_hash_t *left_props,
819 /*const*/ apr_hash_t *right_props,
820 svn_boolean_t file_modified,
821 const apr_array_header_t *prop_changes,
823 const svn_diff_tree_processor_t *processor,
824 apr_pool_t *scratch_pool)
826 struct filter_tree_baton_t *fb = processor->baton;
828 relpath = svn_relpath_skip_ancestor(fb->prefix_relpath, relpath);
829 assert(relpath != NULL); /* Driver error */
831 SVN_ERR(fb->processor->file_changed(relpath,
847 filter_file_closed(const char *relpath,
848 const svn_diff_source_t *left_source,
849 const svn_diff_source_t *right_source,
851 const svn_diff_tree_processor_t *processor,
852 apr_pool_t *scratch_pool)
854 struct filter_tree_baton_t *fb = processor->baton;
856 relpath = svn_relpath_skip_ancestor(fb->prefix_relpath, relpath);
857 assert(relpath != NULL); /* Driver error */
859 SVN_ERR(fb->processor->file_closed(relpath,
870 filter_node_absent(const char *relpath,
872 const svn_diff_tree_processor_t *processor,
873 apr_pool_t *scratch_pool)
875 struct filter_tree_baton_t *fb = processor->baton;
877 relpath = svn_relpath_skip_ancestor(fb->prefix_relpath, relpath);
878 assert(relpath != NULL); /* Driver error */
880 SVN_ERR(fb->processor->node_absent(relpath,
888 const svn_diff_tree_processor_t *
889 svn_diff__tree_processor_filter_create(const svn_diff_tree_processor_t * processor,
890 const char *prefix_relpath,
891 apr_pool_t *result_pool)
893 struct filter_tree_baton_t *fb;
894 svn_diff_tree_processor_t *filter;
896 fb = apr_pcalloc(result_pool, sizeof(*fb));
897 fb->processor = processor;
899 fb->prefix_relpath = apr_pstrdup(result_pool, prefix_relpath);
901 filter = svn_diff__tree_processor_create(fb, result_pool);
903 filter->dir_opened = filter_dir_opened;
904 filter->dir_added = filter_dir_added;
905 filter->dir_deleted = filter_dir_deleted;
906 filter->dir_changed = filter_dir_changed;
907 filter->dir_closed = filter_dir_closed;
909 filter->file_opened = filter_file_opened;
910 filter->file_added = filter_file_added;
911 filter->file_deleted = filter_file_deleted;
912 filter->file_changed = filter_file_changed;
913 filter->file_closed = filter_file_closed;
915 filter->node_absent = filter_node_absent;
920 struct copy_as_changed_baton_t
922 const svn_diff_tree_processor_t *processor;
926 copy_as_changed_dir_opened(void **new_dir_baton,
928 svn_boolean_t *skip_children,
930 const svn_diff_source_t *left_source,
931 const svn_diff_source_t *right_source,
932 const svn_diff_source_t *copyfrom_source,
933 void *parent_dir_baton,
934 const svn_diff_tree_processor_t *processor,
935 apr_pool_t *result_pool,
936 apr_pool_t *scratch_pool)
938 struct copy_as_changed_baton_t *cb = processor->baton;
940 if (!left_source && copyfrom_source)
942 assert(right_source != NULL);
944 left_source = copyfrom_source;
945 copyfrom_source = NULL;
948 SVN_ERR(cb->processor->dir_opened(new_dir_baton, skip, skip_children,
950 left_source, right_source,
954 result_pool, scratch_pool));
959 copy_as_changed_dir_added(const char *relpath,
960 const svn_diff_source_t *copyfrom_source,
961 const svn_diff_source_t *right_source,
962 /*const*/ apr_hash_t *copyfrom_props,
963 /*const*/ apr_hash_t *right_props,
965 const svn_diff_tree_processor_t *processor,
966 apr_pool_t *scratch_pool)
968 struct copy_as_changed_baton_t *cb = processor->baton;
972 apr_array_header_t *propchanges;
973 SVN_ERR(svn_prop_diffs(&propchanges, right_props, copyfrom_props,
975 SVN_ERR(cb->processor->dir_changed(relpath,
987 SVN_ERR(cb->processor->dir_added(relpath,
1000 static svn_error_t *
1001 copy_as_changed_dir_deleted(const char *relpath,
1002 const svn_diff_source_t *left_source,
1003 /*const*/ apr_hash_t *left_props,
1005 const svn_diff_tree_processor_t *processor,
1006 apr_pool_t *scratch_pool)
1008 struct copy_as_changed_baton_t *cb = processor->baton;
1010 SVN_ERR(cb->processor->dir_deleted(relpath,
1017 return SVN_NO_ERROR;
1020 static svn_error_t *
1021 copy_as_changed_dir_changed(const char *relpath,
1022 const svn_diff_source_t *left_source,
1023 const svn_diff_source_t *right_source,
1024 /*const*/ apr_hash_t *left_props,
1025 /*const*/ apr_hash_t *right_props,
1026 const apr_array_header_t *prop_changes,
1028 const struct svn_diff_tree_processor_t *processor,
1029 apr_pool_t *scratch_pool)
1031 struct copy_as_changed_baton_t *cb = processor->baton;
1033 SVN_ERR(cb->processor->dir_changed(relpath,
1042 return SVN_NO_ERROR;
1045 static svn_error_t *
1046 copy_as_changed_dir_closed(const char *relpath,
1047 const svn_diff_source_t *left_source,
1048 const svn_diff_source_t *right_source,
1050 const svn_diff_tree_processor_t *processor,
1051 apr_pool_t *scratch_pool)
1053 struct copy_as_changed_baton_t *cb = processor->baton;
1055 SVN_ERR(cb->processor->dir_closed(relpath,
1061 return SVN_NO_ERROR;
1064 static svn_error_t *
1065 copy_as_changed_file_opened(void **new_file_baton,
1066 svn_boolean_t *skip,
1067 const char *relpath,
1068 const svn_diff_source_t *left_source,
1069 const svn_diff_source_t *right_source,
1070 const svn_diff_source_t *copyfrom_source,
1072 const svn_diff_tree_processor_t *processor,
1073 apr_pool_t *result_pool,
1074 apr_pool_t *scratch_pool)
1076 struct copy_as_changed_baton_t *cb = processor->baton;
1078 if (!left_source && copyfrom_source)
1080 assert(right_source != NULL);
1082 left_source = copyfrom_source;
1083 copyfrom_source = NULL;
1086 SVN_ERR(cb->processor->file_opened(new_file_baton,
1096 return SVN_NO_ERROR;
1099 static svn_error_t *
1100 copy_as_changed_file_added(const char *relpath,
1101 const svn_diff_source_t *copyfrom_source,
1102 const svn_diff_source_t *right_source,
1103 const char *copyfrom_file,
1104 const char *right_file,
1105 /*const*/ apr_hash_t *copyfrom_props,
1106 /*const*/ apr_hash_t *right_props,
1108 const svn_diff_tree_processor_t *processor,
1109 apr_pool_t *scratch_pool)
1111 struct copy_as_changed_baton_t *cb = processor->baton;
1113 if (copyfrom_source)
1115 apr_array_header_t *propchanges;
1117 SVN_ERR(svn_prop_diffs(&propchanges, right_props, copyfrom_props,
1120 /* "" is sometimes a marker for just modified (E.g. no-textdeltas),
1121 and it is certainly not a file */
1122 if (*copyfrom_file && *right_file)
1124 SVN_ERR(svn_io_files_contents_same_p(&same, copyfrom_file,
1125 right_file, scratch_pool));
1130 SVN_ERR(cb->processor->file_changed(relpath,
1145 SVN_ERR(cb->processor->file_added(relpath,
1156 return SVN_NO_ERROR;
1159 static svn_error_t *
1160 copy_as_changed_file_deleted(const char *relpath,
1161 const svn_diff_source_t *left_source,
1162 const char *left_file,
1163 /*const*/ apr_hash_t *left_props,
1165 const svn_diff_tree_processor_t *processor,
1166 apr_pool_t *scratch_pool)
1168 struct copy_as_changed_baton_t *cb = processor->baton;
1170 SVN_ERR(cb->processor->file_deleted(relpath,
1178 return SVN_NO_ERROR;
1181 static svn_error_t *
1182 copy_as_changed_file_changed(const char *relpath,
1183 const svn_diff_source_t *left_source,
1184 const svn_diff_source_t *right_source,
1185 const char *left_file,
1186 const char *right_file,
1187 /*const*/ apr_hash_t *left_props,
1188 /*const*/ apr_hash_t *right_props,
1189 svn_boolean_t file_modified,
1190 const apr_array_header_t *prop_changes,
1192 const svn_diff_tree_processor_t *processor,
1193 apr_pool_t *scratch_pool)
1195 struct copy_as_changed_baton_t *cb = processor->baton;
1197 SVN_ERR(cb->processor->file_changed(relpath,
1209 return SVN_NO_ERROR;
1212 static svn_error_t *
1213 copy_as_changed_file_closed(const char *relpath,
1214 const svn_diff_source_t *left_source,
1215 const svn_diff_source_t *right_source,
1217 const svn_diff_tree_processor_t *processor,
1218 apr_pool_t *scratch_pool)
1220 struct copy_as_changed_baton_t *cb = processor->baton;
1222 SVN_ERR(cb->processor->file_closed(relpath,
1229 return SVN_NO_ERROR;
1232 static svn_error_t *
1233 copy_as_changed_node_absent(const char *relpath,
1235 const svn_diff_tree_processor_t *processor,
1236 apr_pool_t *scratch_pool)
1238 struct copy_as_changed_baton_t *cb = processor->baton;
1240 SVN_ERR(cb->processor->node_absent(relpath,
1244 return SVN_NO_ERROR;
1248 const svn_diff_tree_processor_t *
1249 svn_diff__tree_processor_copy_as_changed_create(
1250 const svn_diff_tree_processor_t * processor,
1251 apr_pool_t *result_pool)
1253 struct copy_as_changed_baton_t *cb;
1254 svn_diff_tree_processor_t *filter;
1256 cb = apr_pcalloc(result_pool, sizeof(*cb));
1257 cb->processor = processor;
1259 filter = svn_diff__tree_processor_create(cb, result_pool);
1260 filter->dir_opened = copy_as_changed_dir_opened;
1261 filter->dir_added = copy_as_changed_dir_added;
1262 filter->dir_deleted = copy_as_changed_dir_deleted;
1263 filter->dir_changed = copy_as_changed_dir_changed;
1264 filter->dir_closed = copy_as_changed_dir_closed;
1266 filter->file_opened = copy_as_changed_file_opened;
1267 filter->file_added = copy_as_changed_file_added;
1268 filter->file_deleted = copy_as_changed_file_deleted;
1269 filter->file_changed = copy_as_changed_file_changed;
1270 filter->file_closed = copy_as_changed_file_closed;
1272 filter->node_absent = copy_as_changed_node_absent;
1278 /* Processor baton for the tee tree processor */
1281 const svn_diff_tree_processor_t *p1;
1282 const svn_diff_tree_processor_t *p2;
1285 /* Wrapper baton for file and directory batons in the tee processor */
1286 struct tee_node_baton_t
1292 static svn_error_t *
1293 tee_dir_opened(void **new_dir_baton,
1294 svn_boolean_t *skip,
1295 svn_boolean_t *skip_children,
1296 const char *relpath,
1297 const svn_diff_source_t *left_source,
1298 const svn_diff_source_t *right_source,
1299 const svn_diff_source_t *copyfrom_source,
1300 void *parent_dir_baton,
1301 const svn_diff_tree_processor_t *processor,
1302 apr_pool_t *result_pool,
1303 apr_pool_t *scratch_pool)
1305 struct tee_baton_t *tb = processor->baton;
1306 struct tee_node_baton_t *pb = parent_dir_baton;
1307 struct tee_node_baton_t *nb = apr_pcalloc(result_pool, sizeof(*nb));
1309 SVN_ERR(tb->p1->dir_opened(&(nb->baton1),
1316 pb ? pb->baton1 : NULL,
1321 SVN_ERR(tb->p2->dir_opened(&(nb->baton2),
1328 pb ? pb->baton2 : NULL,
1333 *new_dir_baton = nb;
1335 return SVN_NO_ERROR;
1338 static svn_error_t *
1339 tee_dir_added(const char *relpath,
1340 const svn_diff_source_t *copyfrom_source,
1341 const svn_diff_source_t *right_source,
1342 /*const*/ apr_hash_t *copyfrom_props,
1343 /*const*/ apr_hash_t *right_props,
1345 const svn_diff_tree_processor_t *processor,
1346 apr_pool_t *scratch_pool)
1348 struct tee_baton_t *tb = processor->baton;
1349 struct tee_node_baton_t *db = dir_baton;
1351 SVN_ERR(tb->p1->dir_added(relpath,
1360 SVN_ERR(tb->p2->dir_added(relpath,
1369 return SVN_NO_ERROR;
1372 static svn_error_t *
1373 tee_dir_deleted(const char *relpath,
1374 const svn_diff_source_t *left_source,
1375 /*const*/ apr_hash_t *left_props,
1377 const svn_diff_tree_processor_t *processor,
1378 apr_pool_t *scratch_pool)
1380 struct tee_baton_t *tb = processor->baton;
1381 struct tee_node_baton_t *db = dir_baton;
1383 SVN_ERR(tb->p1->dir_deleted(relpath,
1390 SVN_ERR(tb->p2->dir_deleted(relpath,
1397 return SVN_NO_ERROR;
1400 static svn_error_t *
1401 tee_dir_changed(const char *relpath,
1402 const svn_diff_source_t *left_source,
1403 const svn_diff_source_t *right_source,
1404 /*const*/ apr_hash_t *left_props,
1405 /*const*/ apr_hash_t *right_props,
1406 const apr_array_header_t *prop_changes,
1408 const struct svn_diff_tree_processor_t *processor,
1409 apr_pool_t *scratch_pool)
1411 struct tee_baton_t *tb = processor->baton;
1412 struct tee_node_baton_t *db = dir_baton;
1414 SVN_ERR(tb->p1->dir_changed(relpath,
1424 SVN_ERR(tb->p2->dir_changed(relpath,
1433 return SVN_NO_ERROR;
1436 static svn_error_t *
1437 tee_dir_closed(const char *relpath,
1438 const svn_diff_source_t *left_source,
1439 const svn_diff_source_t *right_source,
1441 const svn_diff_tree_processor_t *processor,
1442 apr_pool_t *scratch_pool)
1444 struct tee_baton_t *tb = processor->baton;
1445 struct tee_node_baton_t *db = dir_baton;
1447 SVN_ERR(tb->p1->dir_closed(relpath,
1454 SVN_ERR(tb->p2->dir_closed(relpath,
1460 return SVN_NO_ERROR;
1463 static svn_error_t *
1464 tee_file_opened(void **new_file_baton,
1465 svn_boolean_t *skip,
1466 const char *relpath,
1467 const svn_diff_source_t *left_source,
1468 const svn_diff_source_t *right_source,
1469 const svn_diff_source_t *copyfrom_source,
1471 const svn_diff_tree_processor_t *processor,
1472 apr_pool_t *result_pool,
1473 apr_pool_t *scratch_pool)
1475 struct tee_baton_t *tb = processor->baton;
1476 struct tee_node_baton_t *pb = dir_baton;
1477 struct tee_node_baton_t *nb = apr_pcalloc(result_pool, sizeof(*nb));
1479 SVN_ERR(tb->p1->file_opened(&(nb->baton1),
1485 pb ? pb->baton1 : NULL,
1490 SVN_ERR(tb->p2->file_opened(&(nb->baton2),
1496 pb ? pb->baton2 : NULL,
1501 *new_file_baton = nb;
1503 return SVN_NO_ERROR;
1506 static svn_error_t *
1507 tee_file_added(const char *relpath,
1508 const svn_diff_source_t *copyfrom_source,
1509 const svn_diff_source_t *right_source,
1510 const char *copyfrom_file,
1511 const char *right_file,
1512 /*const*/ apr_hash_t *copyfrom_props,
1513 /*const*/ apr_hash_t *right_props,
1515 const svn_diff_tree_processor_t *processor,
1516 apr_pool_t *scratch_pool)
1518 struct tee_baton_t *tb = processor->baton;
1519 struct tee_node_baton_t *fb = file_baton;
1521 SVN_ERR(tb->p1->file_added(relpath,
1532 SVN_ERR(tb->p2->file_added(relpath,
1542 return SVN_NO_ERROR;
1545 static svn_error_t *
1546 tee_file_deleted(const char *relpath,
1547 const svn_diff_source_t *left_source,
1548 const char *left_file,
1549 /*const*/ apr_hash_t *left_props,
1551 const svn_diff_tree_processor_t *processor,
1552 apr_pool_t *scratch_pool)
1554 struct tee_baton_t *tb = processor->baton;
1555 struct tee_node_baton_t *fb = file_baton;
1557 SVN_ERR(tb->p1->file_deleted(relpath,
1565 SVN_ERR(tb->p2->file_deleted(relpath,
1572 return SVN_NO_ERROR;
1575 static svn_error_t *
1576 tee_file_changed(const char *relpath,
1577 const svn_diff_source_t *left_source,
1578 const svn_diff_source_t *right_source,
1579 const char *left_file,
1580 const char *right_file,
1581 /*const*/ apr_hash_t *left_props,
1582 /*const*/ apr_hash_t *right_props,
1583 svn_boolean_t file_modified,
1584 const apr_array_header_t *prop_changes,
1586 const svn_diff_tree_processor_t *processor,
1587 apr_pool_t *scratch_pool)
1589 struct tee_baton_t *tb = processor->baton;
1590 struct tee_node_baton_t *fb = file_baton;
1592 SVN_ERR(tb->p1->file_changed(relpath,
1605 SVN_ERR(tb->p2->file_changed(relpath,
1617 return SVN_NO_ERROR;
1620 static svn_error_t *
1621 tee_file_closed(const char *relpath,
1622 const svn_diff_source_t *left_source,
1623 const svn_diff_source_t *right_source,
1625 const svn_diff_tree_processor_t *processor,
1626 apr_pool_t *scratch_pool)
1628 struct tee_baton_t *tb = processor->baton;
1629 struct tee_node_baton_t *fb = file_baton;
1631 SVN_ERR(tb->p1->file_closed(relpath,
1638 SVN_ERR(tb->p2->file_closed(relpath,
1645 return SVN_NO_ERROR;
1648 static svn_error_t *
1649 tee_node_absent(const char *relpath,
1651 const svn_diff_tree_processor_t *processor,
1652 apr_pool_t *scratch_pool)
1654 struct tee_baton_t *tb = processor->baton;
1655 struct tee_node_baton_t *db = dir_baton;
1657 SVN_ERR(tb->p1->node_absent(relpath,
1658 db ? db->baton1 : NULL,
1662 SVN_ERR(tb->p2->node_absent(relpath,
1663 db ? db->baton2 : NULL,
1667 return SVN_NO_ERROR;
1670 const svn_diff_tree_processor_t *
1671 svn_diff__tree_processor_tee_create(const svn_diff_tree_processor_t *processor1,
1672 const svn_diff_tree_processor_t *processor2,
1673 apr_pool_t *result_pool)
1675 struct tee_baton_t *tb = apr_pcalloc(result_pool, sizeof(*tb));
1676 svn_diff_tree_processor_t *tee;
1677 tb->p1 = processor1;
1678 tb->p2 = processor2;
1680 tee = svn_diff__tree_processor_create(tb, result_pool);
1682 tee->dir_opened = tee_dir_opened;
1683 tee->dir_added = tee_dir_added;
1684 tee->dir_deleted = tee_dir_deleted;
1685 tee->dir_changed = tee_dir_changed;
1686 tee->dir_closed = tee_dir_closed;
1687 tee->file_opened = tee_file_opened;
1688 tee->file_added = tee_file_added;
1689 tee->file_deleted = tee_file_deleted;
1690 tee->file_changed = tee_file_changed;
1691 tee->file_closed = tee_file_closed;
1692 tee->node_absent = tee_node_absent;
1698 svn_diff__source_create(svn_revnum_t revision,
1699 apr_pool_t *result_pool)
1701 svn_diff_source_t *src = apr_pcalloc(result_pool, sizeof(*src));
1703 src->revision = revision;