summaryrefslogtreecommitdiff
path: root/subversion/libsvn_subr/mergeinfo.c
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/libsvn_subr/mergeinfo.c')
-rw-r--r--subversion/libsvn_subr/mergeinfo.c1141
1 files changed, 606 insertions, 535 deletions
diff --git a/subversion/libsvn_subr/mergeinfo.c b/subversion/libsvn_subr/mergeinfo.c
index b7cca49..131fe59 100644
--- a/subversion/libsvn_subr/mergeinfo.c
+++ b/subversion/libsvn_subr/mergeinfo.c
@@ -35,8 +35,10 @@
#include "private/svn_fspath.h"
#include "private/svn_mergeinfo_private.h"
#include "private/svn_string_private.h"
+#include "private/svn_subr_private.h"
#include "svn_private_config.h"
#include "svn_hash.h"
+#include "private/svn_dep_compat.h"
/* Attempt to combine two ranges, IN1 and IN2. If they are adjacent or
overlapping, and their inheritability allows them to be combined, put
@@ -238,15 +240,13 @@ get_type_of_intersection(const svn_merge_range_t *r1,
When replacing the last range in RANGELIST, either allocate a new range in
RESULT_POOL or modify the existing range in place. Any new ranges added
- to RANGELIST are allocated in RESULT_POOL. SCRATCH_POOL is used for any
- temporary allocations.
+ to RANGELIST are allocated in RESULT_POOL.
*/
static svn_error_t *
combine_with_lastrange(const svn_merge_range_t *new_range,
- apr_array_header_t *rangelist,
+ svn_rangelist_t *rangelist,
svn_boolean_t consider_inheritance,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
+ apr_pool_t *result_pool)
{
svn_merge_range_t *lastrange;
svn_merge_range_t combined_range;
@@ -299,163 +299,163 @@ combine_with_lastrange(const svn_merge_range_t *new_range,
SVN_ERR(get_type_of_intersection(new_range, lastrange,
&intersection_type));
- switch (intersection_type)
+ switch (intersection_type)
+ {
+ case svn__no_intersection:
+ /* NEW_RANGE and *LASTRANGE *really* don't intersect so
+ just push NEW_RANGE only RANGELIST. */
+ APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) =
+ svn_merge_range_dup(new_range, result_pool);
+ sorted = (svn_sort_compare_ranges(&lastrange,
+ &new_range) < 0);
+ break;
+
+ case svn__equal_intersection:
+ /* They range are equal so all we do is force the
+ inheritability of lastrange to true. */
+ lastrange->inheritable = TRUE;
+ sorted = TRUE;
+ break;
+
+ case svn__adjoining_intersection:
+ /* They adjoin but don't overlap so just push NEW_RANGE
+ onto RANGELIST. */
+ APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) =
+ svn_merge_range_dup(new_range, result_pool);
+ sorted = (svn_sort_compare_ranges(&lastrange,
+ &new_range) < 0);
+ break;
+
+ case svn__overlapping_intersection:
+ /* They ranges overlap but neither is a proper subset of
+ the other. We'll end up pusing two new ranges onto
+ RANGELIST, the intersecting part and the part unique to
+ NEW_RANGE.*/
{
- case svn__no_intersection:
- /* NEW_RANGE and *LASTRANGE *really* don't intersect so
- just push NEW_RANGE only RANGELIST. */
- APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) =
- svn_merge_range_dup(new_range, result_pool);
- sorted = (svn_sort_compare_ranges(&lastrange,
- &new_range) < 0);
- break;
-
- case svn__equal_intersection:
- /* They range are equal so all we do is force the
- inheritability of lastrange to true. */
- lastrange->inheritable = TRUE;
- sorted = TRUE;
- break;
-
- case svn__adjoining_intersection:
- /* They adjoin but don't overlap so just push NEW_RANGE
- onto RANGELIST. */
- APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) =
- svn_merge_range_dup(new_range, result_pool);
- sorted = (svn_sort_compare_ranges(&lastrange,
- &new_range) < 0);
- break;
-
- case svn__overlapping_intersection:
- /* They ranges overlap but neither is a proper subset of
- the other. We'll end up pusing two new ranges onto
- RANGELIST, the intersecting part and the part unique to
- NEW_RANGE.*/
+ svn_merge_range_t *r1 = svn_merge_range_dup(lastrange,
+ result_pool);
+ svn_merge_range_t *r2 = svn_merge_range_dup(new_range,
+ result_pool);
+
+ /* Pop off *LASTRANGE to make our manipulations
+ easier. */
+ apr_array_pop(rangelist);
+
+ /* Ensure R1 is the older range. */
+ if (r2->start < r1->start)
{
- svn_merge_range_t *r1 = svn_merge_range_dup(lastrange,
- result_pool);
- svn_merge_range_t *r2 = svn_merge_range_dup(new_range,
- result_pool);
+ /* Swap R1 and R2. */
+ *r2 = *r1;
+ *r1 = *new_range;
+ }
- /* Pop off *LASTRANGE to make our manipulations
- easier. */
- apr_array_pop(rangelist);
+ /* Absorb the intersecting ranges into the
+ inheritable range. */
+ if (r1->inheritable)
+ r2->start = r1->end;
+ else
+ r1->end = r2->start;
+
+ /* Push everything back onto RANGELIST. */
+ APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) = r1;
+ sorted = (svn_sort_compare_ranges(&lastrange,
+ &r1) < 0);
+ APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) = r2;
+ if (sorted)
+ sorted = (svn_sort_compare_ranges(&r1, &r2) < 0);
+ break;
+ }
- /* Ensure R1 is the older range. */
- if (r2->start < r1->start)
- {
- /* Swap R1 and R2. */
- *r2 = *r1;
- *r1 = *new_range;
- }
+ default: /* svn__proper_subset_intersection */
+ {
+ /* One range is a proper subset of the other. */
+ svn_merge_range_t *r1 = svn_merge_range_dup(lastrange,
+ result_pool);
+ svn_merge_range_t *r2 = svn_merge_range_dup(new_range,
+ result_pool);
+ svn_merge_range_t *r3 = NULL;
+
+ /* Pop off *LASTRANGE to make our manipulations
+ easier. */
+ apr_array_pop(rangelist);
+
+ /* Ensure R1 is the superset. */
+ if (r2->start < r1->start || r2->end > r1->end)
+ {
+ /* Swap R1 and R2. */
+ *r2 = *r1;
+ *r1 = *new_range;
+ }
- /* Absorb the intersecting ranges into the
- inheritable range. */
- if (r1->inheritable)
- r2->start = r1->end;
- else
- r1->end = r2->start;
+ if (r1->inheritable)
+ {
+ /* The simple case: The superset is inheritable, so
+ just combine r1 and r2. */
+ r1->start = MIN(r1->start, r2->start);
+ r1->end = MAX(r1->end, r2->end);
+ r2 = NULL;
+ }
+ else if (r1->start == r2->start)
+ {
+ svn_revnum_t tmp_revnum;
+
+ /* *LASTRANGE and NEW_RANGE share an end point. */
+ tmp_revnum = r1->end;
+ r1->end = r2->end;
+ r2->inheritable = r1->inheritable;
+ r1->inheritable = TRUE;
+ r2->start = r1->end;
+ r2->end = tmp_revnum;
+ }
+ else if (r1->end == r2->end)
+ {
+ /* *LASTRANGE and NEW_RANGE share an end point. */
+ r1->end = r2->start;
+ r2->inheritable = TRUE;
+ }
+ else
+ {
+ /* NEW_RANGE and *LASTRANGE share neither start
+ nor end points. */
+ r3 = apr_pcalloc(result_pool, sizeof(*r3));
+ r3->start = r2->end;
+ r3->end = r1->end;
+ r3->inheritable = r1->inheritable;
+ r2->inheritable = TRUE;
+ r1->end = r2->start;
+ }
- /* Push everything back onto RANGELIST. */
- APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) = r1;
- sorted = (svn_sort_compare_ranges(&lastrange,
- &r1) < 0);
+ /* Push everything back onto RANGELIST. */
+ APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) = r1;
+ sorted = (svn_sort_compare_ranges(&lastrange, &r1) < 0);
+ if (r2)
+ {
APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) = r2;
if (sorted)
sorted = (svn_sort_compare_ranges(&r1, &r2) < 0);
- break;
}
-
- default: /* svn__proper_subset_intersection */
+ if (r3)
{
- /* One range is a proper subset of the other. */
- svn_merge_range_t *r1 = svn_merge_range_dup(lastrange,
- result_pool);
- svn_merge_range_t *r2 = svn_merge_range_dup(new_range,
- result_pool);
- svn_merge_range_t *r3 = NULL;
-
- /* Pop off *LASTRANGE to make our manipulations
- easier. */
- apr_array_pop(rangelist);
-
- /* Ensure R1 is the superset. */
- if (r2->start < r1->start || r2->end > r1->end)
- {
- /* Swap R1 and R2. */
- *r2 = *r1;
- *r1 = *new_range;
- }
-
- if (r1->inheritable)
- {
- /* The simple case: The superset is inheritable, so
- just combine r1 and r2. */
- r1->start = MIN(r1->start, r2->start);
- r1->end = MAX(r1->end, r2->end);
- r2 = NULL;
- }
- else if (r1->start == r2->start)
- {
- svn_revnum_t tmp_revnum;
-
- /* *LASTRANGE and NEW_RANGE share an end point. */
- tmp_revnum = r1->end;
- r1->end = r2->end;
- r2->inheritable = r1->inheritable;
- r1->inheritable = TRUE;
- r2->start = r1->end;
- r2->end = tmp_revnum;
- }
- else if (r1->end == r2->end)
- {
- /* *LASTRANGE and NEW_RANGE share an end point. */
- r1->end = r2->start;
- r2->inheritable = TRUE;
- }
- else
- {
- /* NEW_RANGE and *LASTRANGE share neither start
- nor end points. */
- r3 = apr_pcalloc(result_pool, sizeof(*r3));
- r3->start = r2->end;
- r3->end = r1->end;
- r3->inheritable = r1->inheritable;
- r2->inheritable = TRUE;
- r1->end = r2->start;
- }
-
- /* Push everything back onto RANGELIST. */
- APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) = r1;
- sorted = (svn_sort_compare_ranges(&lastrange, &r1) < 0);
- if (r2)
- {
- APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) = r2;
- if (sorted)
- sorted = (svn_sort_compare_ranges(&r1, &r2) < 0);
- }
- if (r3)
+ APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) = r3;
+ if (sorted)
{
- APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) = r3;
- if (sorted)
- {
- if (r2)
- sorted = (svn_sort_compare_ranges(&r2,
- &r3) < 0);
- else
- sorted = (svn_sort_compare_ranges(&r1,
- &r3) < 0);
- }
+ if (r2)
+ sorted = (svn_sort_compare_ranges(&r2,
+ &r3) < 0);
+ else
+ sorted = (svn_sort_compare_ranges(&r1,
+ &r3) < 0);
}
- break;
}
+ break;
}
+ }
- /* Some of the above cases might have put *RANGELIST out of
- order, so re-sort.*/
- if (!sorted)
- qsort(rangelist->elts, rangelist->nelts, rangelist->elt_size,
- svn_sort_compare_ranges);
+ /* Some of the above cases might have put *RANGELIST out of
+ order, so re-sort.*/
+ if (!sorted)
+ qsort(rangelist->elts, rangelist->nelts, rangelist->elt_size,
+ svn_sort_compare_ranges);
}
}
@@ -489,13 +489,10 @@ range_to_string(const svn_merge_range_t *range,
revisionlist -> (revisionelement)(COMMA revisionelement)*
revisionrange -> REVISION "-" REVISION("*")
revisionelement -> revisionrange | REVISION("*")
-
- PATHNAME is the path this revisionlist is mapped to. It is
- used only for producing a more descriptive error message.
*/
static svn_error_t *
parse_rangelist(const char **input, const char *end,
- apr_array_header_t *rangelist, const char *pathname,
+ svn_rangelist_t *rangelist,
apr_pool_t *pool)
{
const char *curr = *input;
@@ -508,9 +505,7 @@ parse_rangelist(const char **input, const char *end,
{
/* Empty range list. */
*input = curr;
- return svn_error_createf(SVN_ERR_MERGEINFO_PARSE_ERROR, NULL,
- _("Mergeinfo for '%s' maps to an "
- "empty revision range"), pathname);
+ return SVN_NO_ERROR;
}
while (curr < end && *curr != '\n')
@@ -604,17 +599,115 @@ parse_rangelist(const char **input, const char *end,
return SVN_NO_ERROR;
}
+svn_error_t *
+svn_rangelist__parse(svn_rangelist_t **rangelist,
+ const char *str,
+ apr_pool_t *result_pool)
+{
+ const char *s = str;
+
+ *rangelist = apr_array_make(result_pool, 1, sizeof(svn_merge_range_t *));
+ SVN_ERR(parse_rangelist(&s, s + strlen(s), *rangelist, result_pool));
+ return SVN_NO_ERROR;
+}
+
+/* Return TRUE, if all ranges in RANGELIST are in ascending order and do
+ * not overlap and are not adjacent.
+ *
+ * ### Can yield false negatives: ranges of differing inheritance are
+ * allowed to be adjacent.
+ *
+ * If this returns FALSE, you probaly want to qsort() the
+ * ranges and then call svn_rangelist__combine_adjacent_ranges().
+ */
+static svn_boolean_t
+is_rangelist_normalized(svn_rangelist_t *rangelist)
+{
+ int i;
+ svn_merge_range_t **ranges = (svn_merge_range_t **)rangelist->elts;
+
+ for (i = 0; i < rangelist->nelts-1; ++i)
+ if (ranges[i]->end >= ranges[i+1]->start)
+ return FALSE;
+
+ return TRUE;
+}
+
+svn_error_t *
+svn_rangelist__canonicalize(svn_rangelist_t *rangelist,
+ apr_pool_t *scratch_pool)
+{
+ if (! is_rangelist_normalized(rangelist))
+ {
+ qsort(rangelist->elts, rangelist->nelts, rangelist->elt_size,
+ svn_sort_compare_ranges);
+
+ SVN_ERR(svn_rangelist__combine_adjacent_ranges(rangelist, scratch_pool));
+ }
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_rangelist__combine_adjacent_ranges(svn_rangelist_t *rangelist,
+ apr_pool_t *scratch_pool)
+{
+ int i;
+ svn_merge_range_t *range, *lastrange;
+
+ lastrange = APR_ARRAY_IDX(rangelist, 0, svn_merge_range_t *);
+
+ for (i = 1; i < rangelist->nelts; i++)
+ {
+ range = APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *);
+ if (lastrange->start <= range->end
+ && range->start <= lastrange->end)
+ {
+ /* The ranges are adjacent or intersect. */
+
+ /* svn_mergeinfo_parse promises to combine overlapping
+ ranges as long as their inheritability is the same. */
+ if (range->start < lastrange->end
+ && range->inheritable != lastrange->inheritable)
+ {
+ return svn_error_createf(SVN_ERR_MERGEINFO_PARSE_ERROR, NULL,
+ _("Unable to parse overlapping "
+ "revision ranges '%s' and '%s' "
+ "with different inheritance "
+ "types"),
+ range_to_string(lastrange,
+ scratch_pool),
+ range_to_string(range,
+ scratch_pool));
+ }
+
+ /* Combine overlapping or adjacent ranges with the
+ same inheritability. */
+ if (lastrange->inheritable == range->inheritable)
+ {
+ lastrange->end = MAX(range->end, lastrange->end);
+ svn_sort__array_delete(rangelist, i, 1);
+ i--;
+ }
+ }
+ lastrange = APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *);
+ }
+
+ return SVN_NO_ERROR;
+}
+
/* revisionline -> PATHNAME COLON revisionlist */
static svn_error_t *
parse_revision_line(const char **input, const char *end, svn_mergeinfo_t hash,
- apr_pool_t *pool)
+ apr_pool_t *scratch_pool)
{
- const char *pathname;
- apr_array_header_t *existing_rangelist;
- apr_array_header_t *rangelist = apr_array_make(pool, 1,
- sizeof(svn_merge_range_t *));
+ const char *pathname = "";
+ apr_ssize_t klen;
+ svn_rangelist_t *existing_rangelist;
+ svn_rangelist_t *rangelist = apr_array_make(scratch_pool, 1,
+ sizeof(svn_merge_range_t *));
- SVN_ERR(parse_pathname(input, end, &pathname, pool));
+ SVN_ERR(parse_pathname(input, end, &pathname, scratch_pool));
if (*(*input) != ':')
return svn_error_create(SVN_ERR_MERGEINFO_PARSE_ERROR, NULL,
@@ -622,8 +715,12 @@ parse_revision_line(const char **input, const char *end, svn_mergeinfo_t hash,
*input = *input + 1;
- SVN_ERR(parse_rangelist(input, end, rangelist, pathname, pool));
+ SVN_ERR(parse_rangelist(input, end, rangelist, scratch_pool));
+ if (rangelist->nelts == 0)
+ return svn_error_createf(SVN_ERR_MERGEINFO_PARSE_ERROR, NULL,
+ _("Mergeinfo for '%s' maps to an "
+ "empty revision range"), pathname);
if (*input != end && *(*input) != '\n')
return svn_error_createf(SVN_ERR_MERGEINFO_PARSE_ERROR, NULL,
_("Could not find end of line in range list line "
@@ -632,55 +729,11 @@ parse_revision_line(const char **input, const char *end, svn_mergeinfo_t hash,
if (*input != end)
*input = *input + 1;
- /* Sort the rangelist, combine adjacent ranges into single ranges,
- and make sure there are no overlapping ranges. */
- if (rangelist->nelts > 1)
- {
- int i;
- svn_merge_range_t *range, *lastrange;
-
- qsort(rangelist->elts, rangelist->nelts, rangelist->elt_size,
- svn_sort_compare_ranges);
- lastrange = APR_ARRAY_IDX(rangelist, 0, svn_merge_range_t *);
-
- for (i = 1; i < rangelist->nelts; i++)
- {
- range = APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *);
- if (lastrange->start <= range->end
- && range->start <= lastrange->end)
- {
- /* The ranges are adjacent or intersect. */
-
- /* svn_mergeinfo_parse promises to combine overlapping
- ranges as long as their inheritability is the same. */
- if (range->start < lastrange->end
- && range->inheritable != lastrange->inheritable)
- {
- return svn_error_createf(SVN_ERR_MERGEINFO_PARSE_ERROR, NULL,
- _("Unable to parse overlapping "
- "revision ranges '%s' and '%s' "
- "with different inheritance "
- "types"),
- range_to_string(lastrange, pool),
- range_to_string(range, pool));
- }
-
- /* Combine overlapping or adjacent ranges with the
- same inheritability. */
- if (lastrange->inheritable == range->inheritable)
- {
- lastrange->end = MAX(range->end, lastrange->end);
- if (i + 1 < rangelist->nelts)
- memmove(rangelist->elts + (rangelist->elt_size * i),
- rangelist->elts + (rangelist->elt_size * (i + 1)),
- rangelist->elt_size * (rangelist->nelts - i));
- rangelist->nelts--;
- i--;
- }
- }
- lastrange = APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *);
- }
- }
+ /* Sort the rangelist, combine adjacent ranges into single ranges, and
+ make sure there are no overlapping ranges. Luckily, most data in
+ svn:mergeinfo will already be in normalized form and this will be quick.
+ */
+ SVN_ERR(svn_rangelist__canonicalize(rangelist, scratch_pool));
/* Handle any funky mergeinfo with relative merge source paths that
might exist due to issue #3547. It's possible that this issue allowed
@@ -688,11 +741,14 @@ parse_revision_line(const char **input, const char *end, svn_mergeinfo_t hash,
leading slash, e.g. "trunk:4033\n/trunk:4039-4995". In the event
we encounter this we merge the rangelists together under a single
absolute path key. */
- existing_rangelist = apr_hash_get(hash, pathname, APR_HASH_KEY_STRING);
+ klen = strlen(pathname);
+ existing_rangelist = apr_hash_get(hash, pathname, klen);
if (existing_rangelist)
- SVN_ERR(svn_rangelist_merge(&rangelist, existing_rangelist, pool));
+ SVN_ERR(svn_rangelist_merge2(rangelist, existing_rangelist,
+ scratch_pool, scratch_pool));
- apr_hash_set(hash, pathname, APR_HASH_KEY_STRING, rangelist);
+ apr_hash_set(hash, apr_pstrmemdup(apr_hash_pool_get(hash), pathname, klen),
+ klen, svn_rangelist_dup(rangelist, apr_hash_pool_get(hash)));
return SVN_NO_ERROR;
}
@@ -702,8 +758,14 @@ static svn_error_t *
parse_top(const char **input, const char *end, svn_mergeinfo_t hash,
apr_pool_t *pool)
{
+ apr_pool_t *iterpool = svn_pool_create(pool);
+
while (*input < end)
- SVN_ERR(parse_revision_line(input, end, hash, pool));
+ {
+ svn_pool_clear(iterpool);
+ SVN_ERR(parse_revision_line(input, end, hash, iterpool));
+ }
+ svn_pool_destroy(iterpool);
return SVN_NO_ERROR;
}
@@ -715,7 +777,7 @@ svn_mergeinfo_parse(svn_mergeinfo_t *mergeinfo,
{
svn_error_t *err;
- *mergeinfo = apr_hash_make(pool);
+ *mergeinfo = svn_hash__make(pool);
err = parse_top(&input, input + strlen(input), *mergeinfo, pool);
/* Always return SVN_ERR_MERGEINFO_PARSE_ERROR as the topmost error. */
@@ -726,28 +788,28 @@ svn_mergeinfo_parse(svn_mergeinfo_t *mergeinfo,
return err;
}
-/* Cleanup after svn_rangelist_merge when it modifies the ending range of
+/* Cleanup after svn_rangelist_merge2 when it modifies the ending range of
a single rangelist element in-place.
- If *INDEX is not a valid element in RANGELIST do nothing. Otherwise ensure
- that RANGELIST[*INDEX]->END does not adjoin or overlap any subsequent
- ranges in RANGELIST.
+ If *RANGE_INDEX is not a valid element in RANGELIST do nothing. Otherwise
+ ensure that RANGELIST[*RANGE_INDEX]->END does not adjoin or overlap any
+ subsequent ranges in RANGELIST.
If overlap is found, then remove, modify, and/or add elements to RANGELIST
as per the invariants for rangelists documented in svn_mergeinfo.h. If
- RANGELIST[*INDEX]->END adjoins a subsequent element then combine the
+ RANGELIST[*RANGE_INDEX]->END adjoins a subsequent element then combine the
elements if their inheritability permits -- The inheritance of intersecting
and adjoining ranges is handled as per svn_mergeinfo_merge2. Upon return
- set *INDEX to the index of the youngest element modified, added, or
- adjoined to RANGELIST[*INDEX].
+ set *RANGE_INDEX to the index of the youngest element modified, added, or
+ adjoined to RANGELIST[*RANGE_INDEX].
Note: Adjoining rangelist elements are those where the end rev of the older
element is equal to the start rev of the younger element.
Any new elements inserted into RANGELIST are allocated in RESULT_POOL.*/
static void
-adjust_remaining_ranges(apr_array_header_t *rangelist,
- int *index,
+adjust_remaining_ranges(svn_rangelist_t *rangelist,
+ int *range_index,
apr_pool_t *result_pool)
{
int i;
@@ -755,13 +817,13 @@ adjust_remaining_ranges(apr_array_header_t *rangelist,
int elements_to_delete = 0;
svn_merge_range_t *modified_range;
- if (*index >= rangelist->nelts)
+ if (*range_index >= rangelist->nelts)
return;
- starting_index = *index + 1;
- modified_range = APR_ARRAY_IDX(rangelist, *index, svn_merge_range_t *);
+ starting_index = *range_index + 1;
+ modified_range = APR_ARRAY_IDX(rangelist, *range_index, svn_merge_range_t *);
- for (i = *index + 1; i < rangelist->nelts; i++)
+ for (i = *range_index + 1; i < rangelist->nelts; i++)
{
svn_merge_range_t *next_range = APR_ARRAY_IDX(rangelist, i,
svn_merge_range_t *);
@@ -783,7 +845,7 @@ adjust_remaining_ranges(apr_array_header_t *rangelist,
else
{
/* Cannot join because inheritance differs. */
- (*index)++;
+ (*range_index)++;
}
break;
}
@@ -829,10 +891,11 @@ adjust_remaining_ranges(apr_array_header_t *rangelist,
new_modified_range->end = modified_range->end;
new_modified_range->inheritable = FALSE;
modified_range->end = next_range->start;
- (*index)+=2;
- svn_sort__array_insert(&new_modified_range, rangelist, *index);
+ (*range_index)+=2;
+ svn_sort__array_insert(&new_modified_range, rangelist,
+ *range_index);
/* Recurse with the new range. */
- adjust_remaining_ranges(rangelist, index, result_pool);
+ adjust_remaining_ranges(rangelist, range_index, result_pool);
break;
}
}
@@ -851,7 +914,7 @@ adjust_remaining_ranges(apr_array_header_t *rangelist,
/* The intersection between MODIFIED_RANGE and NEXT_RANGE is
absorbed by the latter. */
modified_range->end = next_range->start;
- (*index)++;
+ (*range_index)++;
}
break;
}
@@ -871,14 +934,14 @@ adjust_remaining_ranges(apr_array_header_t *rangelist,
/* MODIFIED_RANGE absorbs the portion of NEXT_RANGE it overlaps
and NEXT_RANGE is truncated. */
next_range->start = modified_range->end;
- (*index)++;
+ (*range_index)++;
}
else
{
/* NEXT_RANGE absorbs the portion of MODIFIED_RANGE it overlaps
and MODIFIED_RANGE is truncated. */
modified_range->end = next_range->start;
- (*index)++;
+ (*range_index)++;
}
break;
}
@@ -889,21 +952,21 @@ adjust_remaining_ranges(apr_array_header_t *rangelist,
}
svn_error_t *
-svn_rangelist_merge(apr_array_header_t **rangelist,
- const apr_array_header_t *changes,
- apr_pool_t *pool)
+svn_rangelist_merge2(svn_rangelist_t *rangelist,
+ const svn_rangelist_t *changes,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
int i = 0;
int j = 0;
- apr_pool_t *subpool = svn_pool_create(pool);
- /* We may modify CHANGES, so make a copy in SUBPOOL. */
- changes = svn_rangelist_dup(changes, subpool);
+ /* We may modify CHANGES, so make a copy in SCRATCH_POOL. */
+ changes = svn_rangelist_dup(changes, scratch_pool);
- while (i < (*rangelist)->nelts && j < changes->nelts)
+ while (i < rangelist->nelts && j < changes->nelts)
{
svn_merge_range_t *range =
- APR_ARRAY_IDX(*rangelist, i, svn_merge_range_t *);
+ APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *);
svn_merge_range_t *change =
APR_ARRAY_IDX(changes, j, svn_merge_range_t *);
int res = svn_sort_compare_ranges(&range, &change);
@@ -934,7 +997,7 @@ svn_rangelist_merge(apr_array_header_t **rangelist,
/* RANGE and CHANGE have the same inheritability so
RANGE expands to absord CHANGE. */
range->end = change->end;
- adjust_remaining_ranges(*rangelist, &i, pool);
+ adjust_remaining_ranges(rangelist, &i, result_pool);
j++;
}
else
@@ -967,10 +1030,10 @@ svn_rangelist_merge(apr_array_header_t **rangelist,
/* CHANGE absorbs intersection with RANGE and RANGE
is truncated. */
svn_merge_range_t *range_copy =
- svn_merge_range_dup(range, pool);
+ svn_merge_range_dup(range, result_pool);
range_copy->end = change->start;
range->start = change->start;
- svn_sort__array_insert(&range_copy, *rangelist, i++);
+ svn_sort__array_insert(&range_copy, rangelist, i++);
}
else
{
@@ -989,10 +1052,10 @@ svn_rangelist_merge(apr_array_header_t **rangelist,
{
/* CHANGE is older than RANGE and the two do not
adjoin or overlap, so insert a copy of CHANGE
- into *RANGELIST. */
+ into RANGELIST. */
svn_merge_range_t *change_copy =
- svn_merge_range_dup(change, pool);
- svn_sort__array_insert(&change_copy, *rangelist, i++);
+ svn_merge_range_dup(change, result_pool);
+ svn_sort__array_insert(&change_copy, rangelist, i++);
j++;
}
else if (change->end == range->start)
@@ -1008,10 +1071,10 @@ svn_rangelist_merge(apr_array_header_t **rangelist,
else
{
/* RANGE and CHANGE have different inheritability so insert
- a copy of CHANGE into *RANGELIST. */
+ a copy of CHANGE into RANGELIST. */
svn_merge_range_t *change_copy =
- svn_merge_range_dup(change, pool);
- svn_sort__array_insert(&change_copy, *rangelist, i);
+ svn_merge_range_dup(change, result_pool);
+ svn_sort__array_insert(&change_copy, rangelist, i);
j++;
}
}
@@ -1028,7 +1091,7 @@ svn_rangelist_merge(apr_array_header_t **rangelist,
/* ...but if RANGE is expanded ensure that we don't
violate any rangelist invariants. */
range->end = change->end;
- adjust_remaining_ranges(*rangelist, &i, pool);
+ adjust_remaining_ranges(rangelist, &i, result_pool);
}
j++;
}
@@ -1038,12 +1101,12 @@ svn_rangelist_merge(apr_array_header_t **rangelist,
{
/* RANGE is inheritable so absorbs any part of CHANGE
it overlaps. CHANGE is truncated and the remainder
- inserted into *RANGELIST. */
+ inserted into RANGELIST. */
svn_merge_range_t *change_copy =
- svn_merge_range_dup(change, pool);
+ svn_merge_range_dup(change, result_pool);
change_copy->end = range->start;
change->start = range->start;
- svn_sort__array_insert(&change_copy, *rangelist, i++);
+ svn_sort__array_insert(&change_copy, rangelist, i++);
}
else
{
@@ -1079,32 +1142,32 @@ svn_rangelist_merge(apr_array_header_t **rangelist,
{
/* CHANGE and RANGE overlap. Set RANGE equal to its
intersection with CHANGE and take the remainder
- of RANGE and insert it into *RANGELIST. */
+ of RANGE and insert it into RANGELIST. */
svn_merge_range_t *range_copy =
- svn_merge_range_dup(range, pool);
+ svn_merge_range_dup(range, result_pool);
range_copy->start = change->end;
range->start = change->start;
range->end = change->end;
range->inheritable = TRUE;
- svn_sort__array_insert(&range_copy, *rangelist, ++i);
+ svn_sort__array_insert(&range_copy, rangelist, ++i);
j++;
}
}
- else
+ else
{
/* CHANGE and RANGE share the same start rev, but
CHANGE is considered older because its end rev
is older.
-
+
Insert the intersection of RANGE and CHANGE into
- *RANGELIST and then set RANGE to the non-intersecting
+ RANGELIST and then set RANGE to the non-intersecting
portion of RANGE. */
svn_merge_range_t *range_copy =
- svn_merge_range_dup(range, pool);
+ svn_merge_range_dup(range, result_pool);
range_copy->end = change->end;
range_copy->inheritable = TRUE;
range->start = change->end;
- svn_sort__array_insert(&range_copy, *rangelist, i++);
+ svn_sort__array_insert(&range_copy, rangelist, i++);
j++;
}
}
@@ -1112,17 +1175,16 @@ svn_rangelist_merge(apr_array_header_t **rangelist,
}
}
- /* Copy any remaining elements in CHANGES into *RANGELIST. */
+ /* Copy any remaining elements in CHANGES into RANGELIST. */
for (; j < (changes)->nelts; j++)
{
svn_merge_range_t *change =
APR_ARRAY_IDX(changes, j, svn_merge_range_t *);
svn_merge_range_t *change_copy = svn_merge_range_dup(change,
- pool);
- svn_sort__array_insert(&change_copy, *rangelist, (*rangelist)->nelts);
+ result_pool);
+ svn_sort__array_insert(&change_copy, rangelist, rangelist->nelts);
}
- svn_pool_destroy(subpool);
return SVN_NO_ERROR;
}
@@ -1166,33 +1228,22 @@ range_swap_endpoints(svn_merge_range_t *range)
}
svn_error_t *
-svn_rangelist_reverse(apr_array_header_t *rangelist, apr_pool_t *pool)
+svn_rangelist_reverse(svn_rangelist_t *rangelist, apr_pool_t *pool)
{
- int i, swap_index;
- svn_merge_range_t range;
- for (i = 0; i < rangelist->nelts / 2; i++)
+ int i;
+
+ svn_sort__array_reverse(rangelist, pool);
+
+ for (i = 0; i < rangelist->nelts; i++)
{
- swap_index = rangelist->nelts - i - 1;
- range = *APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *);
- *APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *) =
- *APR_ARRAY_IDX(rangelist, swap_index, svn_merge_range_t *);
- *APR_ARRAY_IDX(rangelist, swap_index, svn_merge_range_t *) = range;
- range_swap_endpoints(APR_ARRAY_IDX(rangelist, swap_index,
- svn_merge_range_t *));
range_swap_endpoints(APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *));
}
- /* If there's an odd number of elements, we still need to swap the
- end points of the remaining range. */
- if (rangelist->nelts % 2 == 1)
- range_swap_endpoints(APR_ARRAY_IDX(rangelist, rangelist->nelts / 2,
- svn_merge_range_t *));
-
return SVN_NO_ERROR;
}
void
-svn_rangelist__set_inheritance(apr_array_header_t *rangelist,
+svn_rangelist__set_inheritance(svn_rangelist_t *rangelist,
svn_boolean_t inheritable)
{
if (rangelist)
@@ -1222,7 +1273,7 @@ svn_mergeinfo__set_inheritance(svn_mergeinfo_t mergeinfo,
hi;
hi = apr_hash_next(hi))
{
- apr_array_header_t *rangelist = svn__apr_hash_index_val(hi);
+ svn_rangelist_t *rangelist = svn__apr_hash_index_val(hi);
if (rangelist)
svn_rangelist__set_inheritance(rangelist, inheritable);
@@ -1242,7 +1293,7 @@ svn_mergeinfo__set_inheritance(svn_mergeinfo_t mergeinfo,
If CONSIDER_INHERITANCE is true, then take the inheritance of the
ranges in RANGELIST1 and RANGELIST2 into account when comparing them
- for intersection, see the doc string for svn_rangelist_intersection().
+ for intersection, see the doc string for svn_rangelist_intersect().
If CONSIDER_INHERITANCE is false, then ranges with differing inheritance
may intersect, but the resulting intersection is non-inheritable only
@@ -1264,9 +1315,9 @@ svn_mergeinfo__set_inheritance(svn_mergeinfo_t mergeinfo,
Allocate the contents of *OUTPUT in POOL. */
static svn_error_t *
-rangelist_intersect_or_remove(apr_array_header_t **output,
- const apr_array_header_t *rangelist1,
- const apr_array_header_t *rangelist2,
+rangelist_intersect_or_remove(svn_rangelist_t **output,
+ const svn_rangelist_t *rangelist1,
+ const svn_rangelist_t *rangelist2,
svn_boolean_t do_remove,
svn_boolean_t consider_inheritance,
apr_pool_t *pool)
@@ -1318,7 +1369,7 @@ rangelist_intersect_or_remove(apr_array_header_t **output,
tmp_range.inheritable =
(elt2->inheritable || elt1->inheritable);
SVN_ERR(combine_with_lastrange(&tmp_range, *output,
- consider_inheritance, pool,
+ consider_inheritance,
pool));
}
@@ -1355,7 +1406,7 @@ rangelist_intersect_or_remove(apr_array_header_t **output,
SVN_ERR(combine_with_lastrange(&tmp_range,
*output, consider_inheritance,
- pool, pool));
+ pool));
}
/* Set up the rest of the rangelist2 range for further
@@ -1376,7 +1427,7 @@ rangelist_intersect_or_remove(apr_array_header_t **output,
SVN_ERR(combine_with_lastrange(&tmp_range,
*output,
consider_inheritance,
- pool, pool));
+ pool));
}
working_elt2.start = elt1->end;
@@ -1428,7 +1479,7 @@ rangelist_intersect_or_remove(apr_array_header_t **output,
if (i2 == lasti2 && i2 < rangelist2->nelts)
{
SVN_ERR(combine_with_lastrange(&working_elt2, *output,
- consider_inheritance, pool, pool));
+ consider_inheritance, pool));
i2++;
}
@@ -1439,7 +1490,7 @@ rangelist_intersect_or_remove(apr_array_header_t **output,
svn_merge_range_t *);
SVN_ERR(combine_with_lastrange(elt, *output,
- consider_inheritance, pool, pool));
+ consider_inheritance, pool));
}
}
@@ -1448,9 +1499,9 @@ rangelist_intersect_or_remove(apr_array_header_t **output,
svn_error_t *
-svn_rangelist_intersect(apr_array_header_t **output,
- const apr_array_header_t *rangelist1,
- const apr_array_header_t *rangelist2,
+svn_rangelist_intersect(svn_rangelist_t **output,
+ const svn_rangelist_t *rangelist1,
+ const svn_rangelist_t *rangelist2,
svn_boolean_t consider_inheritance,
apr_pool_t *pool)
{
@@ -1459,9 +1510,9 @@ svn_rangelist_intersect(apr_array_header_t **output,
}
svn_error_t *
-svn_rangelist_remove(apr_array_header_t **output,
- const apr_array_header_t *eraser,
- const apr_array_header_t *whiteboard,
+svn_rangelist_remove(svn_rangelist_t **output,
+ const svn_rangelist_t *eraser,
+ const svn_rangelist_t *whiteboard,
svn_boolean_t consider_inheritance,
apr_pool_t *pool)
{
@@ -1470,8 +1521,8 @@ svn_rangelist_remove(apr_array_header_t **output,
}
svn_error_t *
-svn_rangelist_diff(apr_array_header_t **deleted, apr_array_header_t **added,
- const apr_array_header_t *from, const apr_array_header_t *to,
+svn_rangelist_diff(svn_rangelist_t **deleted, svn_rangelist_t **added,
+ const svn_rangelist_t *from, const svn_rangelist_t *to,
svn_boolean_t consider_inheritance,
apr_pool_t *pool)
{
@@ -1532,35 +1583,34 @@ mergeinfo_hash_diff_cb(const void *key, apr_ssize_t klen,
/* hash_a is FROM mergeinfo,
hash_b is TO mergeinfo. */
struct mergeinfo_diff_baton *cb = baton;
- apr_array_header_t *from_rangelist, *to_rangelist;
+ svn_rangelist_t *from_rangelist, *to_rangelist;
const char *path = key;
if (status == svn_hash_diff_key_both)
{
/* Record any deltas (additions or deletions). */
- apr_array_header_t *deleted_rangelist, *added_rangelist;
- from_rangelist = apr_hash_get(cb->from, path, APR_HASH_KEY_STRING);
- to_rangelist = apr_hash_get(cb->to, path, APR_HASH_KEY_STRING);
+ svn_rangelist_t *deleted_rangelist, *added_rangelist;
+ from_rangelist = apr_hash_get(cb->from, path, klen);
+ to_rangelist = apr_hash_get(cb->to, path, klen);
SVN_ERR(svn_rangelist_diff(&deleted_rangelist, &added_rangelist,
from_rangelist, to_rangelist,
cb->consider_inheritance, cb->pool));
if (cb->deleted && deleted_rangelist->nelts > 0)
- apr_hash_set(cb->deleted, apr_pstrdup(cb->pool, path),
- APR_HASH_KEY_STRING, deleted_rangelist);
+ apr_hash_set(cb->deleted, apr_pstrmemdup(cb->pool, path, klen),
+ klen, deleted_rangelist);
if (cb->added && added_rangelist->nelts > 0)
- apr_hash_set(cb->added, apr_pstrdup(cb->pool, path),
- APR_HASH_KEY_STRING, added_rangelist);
+ apr_hash_set(cb->added, apr_pstrmemdup(cb->pool, path, klen),
+ klen, added_rangelist);
}
else if ((status == svn_hash_diff_key_a) && cb->deleted)
{
- from_rangelist = apr_hash_get(cb->from, path, APR_HASH_KEY_STRING);
- apr_hash_set(cb->deleted, apr_pstrdup(cb->pool, path),
- APR_HASH_KEY_STRING,
+ from_rangelist = apr_hash_get(cb->from, path, klen);
+ apr_hash_set(cb->deleted, apr_pstrmemdup(cb->pool, path, klen), klen,
svn_rangelist_dup(from_rangelist, cb->pool));
}
else if ((status == svn_hash_diff_key_b) && cb->added)
{
- to_rangelist = apr_hash_get(cb->to, path, APR_HASH_KEY_STRING);
- apr_hash_set(cb->added, apr_pstrdup(cb->pool, path), APR_HASH_KEY_STRING,
+ to_rangelist = apr_hash_get(cb->to, path, klen);
+ apr_hash_set(cb->added, apr_pstrmemdup(cb->pool, path, klen), klen,
svn_rangelist_dup(to_rangelist, cb->pool));
}
return SVN_NO_ERROR;
@@ -1588,31 +1638,32 @@ walk_mergeinfo_hash_for_diff(svn_mergeinfo_t from, svn_mergeinfo_t to,
}
svn_error_t *
-svn_mergeinfo_diff(svn_mergeinfo_t *deleted, svn_mergeinfo_t *added,
- svn_mergeinfo_t from, svn_mergeinfo_t to,
- svn_boolean_t consider_inheritance,
- apr_pool_t *pool)
+svn_mergeinfo_diff2(svn_mergeinfo_t *deleted, svn_mergeinfo_t *added,
+ svn_mergeinfo_t from, svn_mergeinfo_t to,
+ svn_boolean_t consider_inheritance,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
if (from && to == NULL)
{
- *deleted = svn_mergeinfo_dup(from, pool);
- *added = apr_hash_make(pool);
+ *deleted = svn_mergeinfo_dup(from, result_pool);
+ *added = svn_hash__make(result_pool);
}
else if (from == NULL && to)
{
- *deleted = apr_hash_make(pool);
- *added = svn_mergeinfo_dup(to, pool);
+ *deleted = svn_hash__make(result_pool);
+ *added = svn_mergeinfo_dup(to, result_pool);
}
else
{
- *deleted = apr_hash_make(pool);
- *added = apr_hash_make(pool);
+ *deleted = svn_hash__make(result_pool);
+ *added = svn_hash__make(result_pool);
if (from && to)
{
SVN_ERR(walk_mergeinfo_hash_for_diff(from, to, *deleted, *added,
- consider_inheritance, pool,
- pool));
+ consider_inheritance,
+ result_pool, scratch_pool));
}
}
@@ -1626,74 +1677,117 @@ svn_mergeinfo__equals(svn_boolean_t *is_equal,
svn_boolean_t consider_inheritance,
apr_pool_t *pool)
{
- if (apr_hash_count(info1) == apr_hash_count(info2))
+ apr_hash_index_t *hi;
+
+ *is_equal = FALSE;
+
+ /* special cases: at least one side has no merge info */
+ if (info1 == NULL && info2 == NULL)
{
- svn_mergeinfo_t deleted, added;
- SVN_ERR(svn_mergeinfo_diff(&deleted, &added, info1, info2,
- consider_inheritance, pool));
- *is_equal = apr_hash_count(deleted) == 0 && apr_hash_count(added) == 0;
+ *is_equal = TRUE;
+ return SVN_NO_ERROR;
}
- else
+
+ if (info1 == NULL || info2 == NULL)
+ return SVN_NO_ERROR;
+
+ /* trivial case: different number of paths -> unequal */
+ if (apr_hash_count(info1) != apr_hash_count(info2))
+ return SVN_NO_ERROR;
+
+ /* compare range lists for all paths */
+ for (hi = apr_hash_first(pool, info1); hi; hi = apr_hash_next(hi))
{
- *is_equal = FALSE;
+ const char *key;
+ apr_ssize_t key_length;
+ svn_rangelist_t *lhs, *rhs;
+ int i;
+ svn_rangelist_t *deleted, *added;
+
+ /* get both path lists */
+ apr_hash_this(hi, (const void**)&key, &key_length, (void **)&lhs);
+ rhs = apr_hash_get(info2, key, key_length);
+
+ /* missing on one side? */
+ if (rhs == NULL)
+ return SVN_NO_ERROR;
+
+ /* quick compare: the range lists will often be a perfect match */
+ if (lhs->nelts == rhs->nelts)
+ {
+ for (i = 0; i < lhs->nelts; ++i)
+ {
+ svn_merge_range_t *lrange
+ = APR_ARRAY_IDX(lhs, i, svn_merge_range_t *);
+ svn_merge_range_t *rrange
+ = APR_ARRAY_IDX(rhs, i, svn_merge_range_t *);
+
+ /* range mismatch? -> needs detailed comparison */
+ if ( lrange->start != rrange->start
+ || lrange->end != rrange->end)
+ break;
+
+ /* inheritance mismatch? -> merge info differs */
+ if ( consider_inheritance
+ && lrange->inheritable != rrange->inheritable)
+ return SVN_NO_ERROR;
+ }
+
+ /* all ranges found to match -> next path */
+ if (i == lhs->nelts)
+ continue;
+ }
+
+ /* range lists differ but there are many ways to sort and aggregate
+ revisions into ranges. Do a full diff on them. */
+ SVN_ERR(svn_rangelist_diff(&deleted, &added, lhs, rhs,
+ consider_inheritance, pool));
+ if (deleted->nelts || added->nelts)
+ return SVN_NO_ERROR;
}
+
+ /* no mismatch found */
+ *is_equal = TRUE;
return SVN_NO_ERROR;
}
svn_error_t *
-svn_mergeinfo_merge(svn_mergeinfo_t mergeinfo, svn_mergeinfo_t changes,
- apr_pool_t *pool)
+svn_mergeinfo_merge2(svn_mergeinfo_t mergeinfo,
+ svn_mergeinfo_t changes,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
- apr_array_header_t *sorted1, *sorted2;
- int i, j;
+ apr_hash_index_t *hi;
+ apr_pool_t *iterpool;
if (!apr_hash_count(changes))
return SVN_NO_ERROR;
- sorted1 = svn_sort__hash(mergeinfo, svn_sort_compare_items_as_paths, pool);
- sorted2 = svn_sort__hash(changes, svn_sort_compare_items_as_paths, pool);
-
- i = 0;
- j = 0;
- while (i < sorted1->nelts && j < sorted2->nelts)
+ iterpool = svn_pool_create(scratch_pool);
+ for (hi = apr_hash_first(scratch_pool, changes); hi; hi = apr_hash_next(hi))
{
- svn_sort__item_t elt1, elt2;
- int res;
-
- elt1 = APR_ARRAY_IDX(sorted1, i, svn_sort__item_t);
- elt2 = APR_ARRAY_IDX(sorted2, j, svn_sort__item_t);
- res = svn_sort_compare_items_as_paths(&elt1, &elt2);
-
- if (res == 0)
+ const char *key;
+ apr_ssize_t klen;
+ svn_rangelist_t *to_insert;
+ svn_rangelist_t *target;
+
+ /* get ranges to insert and the target ranges list of that insertion */
+ apr_hash_this(hi, (const void**)&key, &klen, (void*)&to_insert);
+ target = apr_hash_get(mergeinfo, key, klen);
+
+ /* if range list exists, just expand on it.
+ * Otherwise, add new hash entry. */
+ if (target)
{
- apr_array_header_t *rl1, *rl2;
-
- rl1 = elt1.value;
- rl2 = elt2.value;
-
- SVN_ERR(svn_rangelist_merge(&rl1, rl2,
- pool));
- apr_hash_set(mergeinfo, elt1.key, elt1.klen, rl1);
- i++;
- j++;
- }
- else if (res < 0)
- {
- i++;
+ SVN_ERR(svn_rangelist_merge2(target, to_insert, result_pool,
+ iterpool));
+ svn_pool_clear(iterpool);
}
else
- {
- apr_hash_set(mergeinfo, elt2.key, elt2.klen, elt2.value);
- j++;
- }
+ apr_hash_set(mergeinfo, key, klen, to_insert);
}
- /* Copy back any remaining elements from the second hash. */
- for (; j < sorted2->nelts; j++)
- {
- svn_sort__item_t elt = APR_ARRAY_IDX(sorted2, j, svn_sort__item_t);
- apr_hash_set(mergeinfo, elt.key, elt.klen, elt.value);
- }
+ svn_pool_destroy(iterpool);
return SVN_NO_ERROR;
}
@@ -1727,8 +1821,8 @@ svn_mergeinfo_catalog_merge(svn_mergeinfo_catalog_t mergeinfo_cat,
svn_mergeinfo_t mergeinfo = cat_elt.value;
svn_mergeinfo_t changes_mergeinfo = change_elt.value;
- SVN_ERR(svn_mergeinfo_merge(mergeinfo, changes_mergeinfo,
- result_pool));
+ SVN_ERR(svn_mergeinfo_merge2(mergeinfo, changes_mergeinfo,
+ result_pool, scratch_pool));
apr_hash_set(mergeinfo_cat, cat_elt.key, cat_elt.klen, mergeinfo);
i++;
j++;
@@ -1762,16 +1856,6 @@ svn_mergeinfo_catalog_merge(svn_mergeinfo_catalog_t mergeinfo_cat,
}
svn_error_t *
-svn_mergeinfo_intersect(svn_mergeinfo_t *mergeinfo,
- svn_mergeinfo_t mergeinfo1,
- svn_mergeinfo_t mergeinfo2,
- apr_pool_t *pool)
-{
- return svn_mergeinfo_intersect2(mergeinfo, mergeinfo1, mergeinfo2,
- TRUE, pool, pool);
-}
-
-svn_error_t *
svn_mergeinfo_intersect2(svn_mergeinfo_t *mergeinfo,
svn_mergeinfo_t mergeinfo1,
svn_mergeinfo_t mergeinfo2,
@@ -1794,20 +1878,18 @@ svn_mergeinfo_intersect2(svn_mergeinfo_t *mergeinfo,
hi; hi = apr_hash_next(hi))
{
const char *path = svn__apr_hash_index_key(hi);
- apr_array_header_t *rangelist1 = svn__apr_hash_index_val(hi);
- apr_array_header_t *rangelist2;
+ svn_rangelist_t *rangelist1 = svn__apr_hash_index_val(hi);
+ svn_rangelist_t *rangelist2;
svn_pool_clear(iterpool);
- rangelist2 = apr_hash_get(mergeinfo2, path, APR_HASH_KEY_STRING);
+ rangelist2 = svn_hash_gets(mergeinfo2, path);
if (rangelist2)
{
SVN_ERR(svn_rangelist_intersect(&rangelist2, rangelist1, rangelist2,
consider_inheritance, iterpool));
if (rangelist2->nelts > 0)
- apr_hash_set(*mergeinfo,
- apr_pstrdup(result_pool, path),
- APR_HASH_KEY_STRING,
- svn_rangelist_dup(rangelist2, result_pool));
+ svn_hash_sets(*mergeinfo, apr_pstrdup(result_pool, path),
+ svn_rangelist_dup(rangelist2, result_pool));
}
}
svn_pool_destroy(iterpool);
@@ -1815,14 +1897,6 @@ svn_mergeinfo_intersect2(svn_mergeinfo_t *mergeinfo,
}
svn_error_t *
-svn_mergeinfo_remove(svn_mergeinfo_t *mergeinfo, svn_mergeinfo_t eraser,
- svn_mergeinfo_t whiteboard, apr_pool_t *pool)
-{
- return svn_mergeinfo_remove2(mergeinfo, eraser, whiteboard, TRUE, pool,
- pool);
-}
-
-svn_error_t *
svn_mergeinfo_remove2(svn_mergeinfo_t *mergeinfo,
svn_mergeinfo_t eraser,
svn_mergeinfo_t whiteboard,
@@ -1838,10 +1912,10 @@ svn_mergeinfo_remove2(svn_mergeinfo_t *mergeinfo,
svn_error_t *
svn_rangelist_to_string(svn_string_t **output,
- const apr_array_header_t *rangelist,
+ const svn_rangelist_t *rangelist,
apr_pool_t *pool)
{
- svn_stringbuf_t *buf = svn_stringbuf_create("", pool);
+ svn_stringbuf_t *buf = svn_stringbuf_create_empty(pool);
if (rangelist->nelts > 0)
{
@@ -1878,7 +1952,7 @@ mergeinfo_to_stringbuf(svn_stringbuf_t **output,
const char *prefix,
apr_pool_t *pool)
{
- *output = svn_stringbuf_create("", pool);
+ *output = svn_stringbuf_create_empty(pool);
if (apr_hash_count(input) > 0)
{
@@ -1911,16 +1985,10 @@ svn_error_t *
svn_mergeinfo_to_string(svn_string_t **output, svn_mergeinfo_t input,
apr_pool_t *pool)
{
- if (apr_hash_count(input) > 0)
- {
- svn_stringbuf_t *mergeinfo_buf;
- SVN_ERR(mergeinfo_to_stringbuf(&mergeinfo_buf, input, NULL, pool));
- *output = svn_stringbuf__morph_into_string(mergeinfo_buf);
- }
- else
- {
- *output = svn_string_create("", pool);
- }
+ svn_stringbuf_t *mergeinfo_buf;
+
+ SVN_ERR(mergeinfo_to_stringbuf(&mergeinfo_buf, input, NULL, pool));
+ *output = svn_stringbuf__morph_into_string(mergeinfo_buf);
return SVN_NO_ERROR;
}
@@ -1938,6 +2006,22 @@ svn_mergeinfo_sort(svn_mergeinfo_t input, apr_pool_t *pool)
return SVN_NO_ERROR;
}
+svn_error_t *
+svn_mergeinfo__canonicalize_ranges(svn_mergeinfo_t mergeinfo,
+ apr_pool_t *scratch_pool)
+{
+ apr_hash_index_t *hi;
+
+ for (hi = apr_hash_first(scratch_pool, mergeinfo); hi; hi = apr_hash_next(hi))
+ {
+ apr_array_header_t *rl = svn__apr_hash_index_val(hi);
+
+ SVN_ERR(svn_rangelist__canonicalize(rl, scratch_pool));
+ }
+
+ return SVN_NO_ERROR;
+}
+
svn_mergeinfo_catalog_t
svn_mergeinfo_catalog_dup(svn_mergeinfo_catalog_t mergeinfo_catalog,
apr_pool_t *pool)
@@ -1952,10 +2036,8 @@ svn_mergeinfo_catalog_dup(svn_mergeinfo_catalog_t mergeinfo_catalog,
const char *key = svn__apr_hash_index_key(hi);
svn_mergeinfo_t val = svn__apr_hash_index_val(hi);
- apr_hash_set(new_mergeinfo_catalog,
- apr_pstrdup(pool, key),
- APR_HASH_KEY_STRING,
- svn_mergeinfo_dup(val, pool));
+ svn_hash_sets(new_mergeinfo_catalog, apr_pstrdup(pool, key),
+ svn_mergeinfo_dup(val, pool));
}
return new_mergeinfo_catalog;
@@ -1964,14 +2046,14 @@ svn_mergeinfo_catalog_dup(svn_mergeinfo_catalog_t mergeinfo_catalog,
svn_mergeinfo_t
svn_mergeinfo_dup(svn_mergeinfo_t mergeinfo, apr_pool_t *pool)
{
- svn_mergeinfo_t new_mergeinfo = apr_hash_make(pool);
+ svn_mergeinfo_t new_mergeinfo = svn_hash__make(pool);
apr_hash_index_t *hi;
for (hi = apr_hash_first(pool, mergeinfo); hi; hi = apr_hash_next(hi))
{
const char *path = svn__apr_hash_index_key(hi);
apr_ssize_t pathlen = svn__apr_hash_index_klen(hi);
- apr_array_header_t *rangelist = svn__apr_hash_index_val(hi);
+ svn_rangelist_t *rangelist = svn__apr_hash_index_val(hi);
apr_hash_set(new_mergeinfo, apr_pstrmemdup(pool, path, pathlen), pathlen,
svn_rangelist_dup(rangelist, pool));
@@ -1999,8 +2081,8 @@ svn_mergeinfo_inheritable2(svn_mergeinfo_t *output,
{
const char *key = svn__apr_hash_index_key(hi);
apr_ssize_t keylen = svn__apr_hash_index_klen(hi);
- apr_array_header_t *rangelist = svn__apr_hash_index_val(hi);
- apr_array_header_t *inheritable_rangelist;
+ svn_rangelist_t *rangelist = svn__apr_hash_index_val(hi);
+ svn_rangelist_t *inheritable_rangelist;
if (!path || svn_path_compare_paths(path, key) == 0)
SVN_ERR(svn_rangelist_inheritable2(&inheritable_rangelist, rangelist,
@@ -2022,8 +2104,8 @@ svn_mergeinfo_inheritable2(svn_mergeinfo_t *output,
svn_error_t *
-svn_rangelist_inheritable2(apr_array_header_t **inheritable_rangelist,
- const apr_array_header_t *rangelist,
+svn_rangelist_inheritable2(svn_rangelist_t **inheritable_rangelist,
+ const svn_rangelist_t *rangelist,
svn_revnum_t start,
svn_revnum_t end,
svn_boolean_t inheritable,
@@ -2060,7 +2142,7 @@ svn_rangelist_inheritable2(apr_array_header_t **inheritable_rangelist,
{
/* We want only the non-inheritable ranges bound by START
and END removed. */
- apr_array_header_t *ranges_inheritable =
+ svn_rangelist_t *ranges_inheritable =
svn_rangelist__initialize(start, end, inheritable, scratch_pool);
if (rangelist->nelts)
@@ -2086,11 +2168,11 @@ svn_mergeinfo__remove_empty_rangelists(svn_mergeinfo_t mergeinfo,
for (hi = apr_hash_first(pool, mergeinfo); hi; hi = apr_hash_next(hi))
{
const char *path = svn__apr_hash_index_key(hi);
- apr_array_header_t *rangelist = svn__apr_hash_index_val(hi);
+ svn_rangelist_t *rangelist = svn__apr_hash_index_val(hi);
if (rangelist->nelts == 0)
{
- apr_hash_set(mergeinfo, path, APR_HASH_KEY_STRING, NULL);
+ svn_hash_sets(mergeinfo, path, NULL);
removed_some_ranges = TRUE;
}
}
@@ -2105,7 +2187,6 @@ svn_mergeinfo__remove_prefix_from_catalog(svn_mergeinfo_catalog_t *out_catalog,
apr_pool_t *pool)
{
apr_hash_index_t *hi;
- apr_ssize_t prefix_len = strlen(prefix_path);
SVN_ERR_ASSERT(prefix_path[0] == '/');
@@ -2114,23 +2195,13 @@ svn_mergeinfo__remove_prefix_from_catalog(svn_mergeinfo_catalog_t *out_catalog,
for (hi = apr_hash_first(pool, in_catalog); hi; hi = apr_hash_next(hi))
{
const char *original_path = svn__apr_hash_index_key(hi);
- apr_ssize_t klen = svn__apr_hash_index_klen(hi);
svn_mergeinfo_t value = svn__apr_hash_index_val(hi);
- apr_ssize_t padding = 0;
-
- SVN_ERR_ASSERT(klen >= prefix_len);
- SVN_ERR_ASSERT(svn_fspath__is_ancestor(prefix_path, original_path));
+ const char *new_path;
- /* If the ORIGINAL_PATH doesn't match the PREFIX_PATH exactly
- and we're not simply removing a single leading slash (such as
- when PREFIX_PATH is "/"), we advance our string offset by an
- extra character (to get past the directory separator that
- follows the prefix). */
- if ((strcmp(original_path, prefix_path) != 0) && (prefix_len != 1))
- padding = 1;
+ new_path = svn_fspath__skip_ancestor(prefix_path, original_path);
+ SVN_ERR_ASSERT(new_path);
- apr_hash_set(*out_catalog, original_path + prefix_len + padding,
- klen - prefix_len - padding, value);
+ svn_hash_sets(*out_catalog, new_path, value);
}
return SVN_NO_ERROR;
@@ -2157,9 +2228,9 @@ svn_mergeinfo__add_prefix_to_catalog(svn_mergeinfo_catalog_t *out_catalog,
if (original_path[0] == '/')
original_path++;
- apr_hash_set(*out_catalog,
- svn_dirent_join(prefix_path, original_path, result_pool),
- APR_HASH_KEY_STRING, value);
+ svn_hash_sets(*out_catalog,
+ svn_dirent_join(prefix_path, original_path, result_pool),
+ value);
}
return SVN_NO_ERROR;
@@ -2182,30 +2253,34 @@ svn_mergeinfo__add_suffix_to_mergeinfo(svn_mergeinfo_t *out_mergeinfo,
hi;
hi = apr_hash_next(hi))
{
- const char *path = svn__apr_hash_index_key(hi);
- apr_array_header_t *rangelist = svn__apr_hash_index_val(hi);
+ const char *fspath = svn__apr_hash_index_key(hi);
+ svn_rangelist_t *rangelist = svn__apr_hash_index_val(hi);
- apr_hash_set(*out_mergeinfo,
- svn_dirent_join(path, suffix_relpath, result_pool),
- APR_HASH_KEY_STRING,
- svn_rangelist_dup(rangelist, result_pool));
+ svn_hash_sets(*out_mergeinfo,
+ svn_fspath__join(fspath, suffix_relpath, result_pool),
+ rangelist);
}
return SVN_NO_ERROR;
}
-apr_array_header_t *
-svn_rangelist_dup(const apr_array_header_t *rangelist, apr_pool_t *pool)
+svn_rangelist_t *
+svn_rangelist_dup(const svn_rangelist_t *rangelist, apr_pool_t *pool)
{
- apr_array_header_t *new_rl = apr_array_make(pool, rangelist->nelts,
- sizeof(svn_merge_range_t *));
+ svn_rangelist_t *new_rl = apr_array_make(pool, rangelist->nelts,
+ sizeof(svn_merge_range_t *));
+
+ /* allocate target range buffer with a single operation */
+ svn_merge_range_t *copy = apr_palloc(pool, sizeof(*copy) * rangelist->nelts);
int i;
+ /* fill it iteratively and link it into the range list */
for (i = 0; i < rangelist->nelts; i++)
{
- APR_ARRAY_PUSH(new_rl, svn_merge_range_t *) =
- svn_merge_range_dup(APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *),
- pool);
+ memcpy(copy + i,
+ APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *),
+ sizeof(*copy));
+ APR_ARRAY_PUSH(new_rl, svn_merge_range_t *) = copy + i;
}
return new_rl;
@@ -2247,7 +2322,7 @@ svn_mergeinfo__catalog_to_formatted_string(svn_string_t **output,
apr_array_header_t *sorted_catalog =
svn_sort__hash(catalog, svn_sort_compare_items_as_paths, pool);
- output_buf = svn_stringbuf_create("", pool);
+ output_buf = svn_stringbuf_create_empty(pool);
for (i = 0; i < sorted_catalog->nelts; i++)
{
svn_sort__item_t elt =
@@ -2293,38 +2368,6 @@ svn_mergeinfo__catalog_to_formatted_string(svn_string_t **output,
}
svn_error_t *
-svn_mergeinfo__to_formatted_string(svn_string_t **output,
- svn_mergeinfo_t mergeinfo,
- const char *prefix,
- apr_pool_t *pool)
-{
- svn_stringbuf_t *output_buf = NULL;
-
- if (mergeinfo && apr_hash_count(mergeinfo))
- {
- SVN_ERR(mergeinfo_to_stringbuf(&output_buf, mergeinfo,
- prefix ? prefix : "", pool));
- svn_stringbuf_appendcstr(output_buf, "\n");
- }
-#if SVN_DEBUG
- else if (!mergeinfo)
- {
- output_buf = svn_stringbuf_create(prefix ? prefix : "", pool);
- svn_stringbuf_appendcstr(output_buf, _("NULL mergeinfo\n"));
- }
- else if (apr_hash_count(mergeinfo) == 0)
- {
- output_buf = svn_stringbuf_create(prefix ? prefix : "", pool);
- svn_stringbuf_appendcstr(output_buf, _("empty mergeinfo\n"));
- }
-#endif
-
- *output = output_buf ? svn_stringbuf__morph_into_string(output_buf)
- : svn_string_create("", pool);
- return SVN_NO_ERROR;
-}
-
-svn_error_t *
svn_mergeinfo__get_range_endpoints(svn_revnum_t *youngest_rev,
svn_revnum_t *oldest_rev,
svn_mergeinfo_t mergeinfo,
@@ -2337,7 +2380,7 @@ svn_mergeinfo__get_range_endpoints(svn_revnum_t *youngest_rev,
for (hi = apr_hash_first(pool, mergeinfo); hi; hi = apr_hash_next(hi))
{
- apr_array_header_t *rangelist = svn__apr_hash_index_val(hi);
+ svn_rangelist_t *rangelist = svn__apr_hash_index_val(hi);
if (rangelist->nelts)
{
@@ -2386,10 +2429,8 @@ svn_mergeinfo__filter_catalog_by_ranges(svn_mergeinfo_catalog_t *filtered_cat,
result_pool,
scratch_pool));
if (apr_hash_count(filtered_mergeinfo))
- apr_hash_set(*filtered_cat,
- apr_pstrdup(result_pool, path),
- APR_HASH_KEY_STRING,
- filtered_mergeinfo);
+ svn_hash_sets(*filtered_cat,
+ apr_pstrdup(result_pool, path), filtered_mergeinfo);
}
return SVN_NO_ERROR;
@@ -2413,7 +2454,7 @@ svn_mergeinfo__filter_mergeinfo_by_ranges(svn_mergeinfo_t *filtered_mergeinfo,
if (mergeinfo)
{
apr_hash_index_t *hi;
- apr_array_header_t *filter_rangelist =
+ svn_rangelist_t *filter_rangelist =
svn_rangelist__initialize(oldest_rev, youngest_rev, TRUE,
scratch_pool);
@@ -2422,21 +2463,19 @@ svn_mergeinfo__filter_mergeinfo_by_ranges(svn_mergeinfo_t *filtered_mergeinfo,
hi = apr_hash_next(hi))
{
const char *path = svn__apr_hash_index_key(hi);
- apr_array_header_t *rangelist = svn__apr_hash_index_val(hi);
+ svn_rangelist_t *rangelist = svn__apr_hash_index_val(hi);
if (rangelist->nelts)
{
- apr_array_header_t *new_rangelist;
+ svn_rangelist_t *new_rangelist;
SVN_ERR(rangelist_intersect_or_remove(
&new_rangelist, filter_rangelist, rangelist,
! include_range, FALSE, result_pool));
if (new_rangelist->nelts)
- apr_hash_set(*filtered_mergeinfo,
- apr_pstrdup(result_pool, path),
- APR_HASH_KEY_STRING,
- new_rangelist);
+ svn_hash_sets(*filtered_mergeinfo,
+ apr_pstrdup(result_pool, path), new_rangelist);
}
}
}
@@ -2461,8 +2500,8 @@ svn_mergeinfo__adjust_mergeinfo_rangelists(svn_mergeinfo_t *adjusted_mergeinfo,
{
int i;
const char *path = svn__apr_hash_index_key(hi);
- apr_array_header_t *rangelist = svn__apr_hash_index_val(hi);
- apr_array_header_t *adjusted_rangelist =
+ svn_rangelist_t *rangelist = svn__apr_hash_index_val(hi);
+ svn_rangelist_t *adjusted_rangelist =
apr_array_make(result_pool, rangelist->nelts,
sizeof(svn_merge_range_t *));
@@ -2488,8 +2527,8 @@ svn_mergeinfo__adjust_mergeinfo_rangelists(svn_mergeinfo_t *adjusted_mergeinfo,
}
if (adjusted_rangelist->nelts)
- apr_hash_set(*adjusted_mergeinfo, apr_pstrdup(result_pool, path),
- APR_HASH_KEY_STRING, adjusted_rangelist);
+ svn_hash_sets(*adjusted_mergeinfo, apr_pstrdup(result_pool, path),
+ adjusted_rangelist);
}
}
return SVN_NO_ERROR;
@@ -2507,7 +2546,7 @@ svn_mergeinfo__is_noninheritable(svn_mergeinfo_t mergeinfo,
hi;
hi = apr_hash_next(hi))
{
- apr_array_header_t *rangelist = svn__apr_hash_index_val(hi);
+ svn_rangelist_t *rangelist = svn__apr_hash_index_val(hi);
int i;
for (i = 0; i < rangelist->nelts; i++)
@@ -2522,32 +2561,13 @@ svn_mergeinfo__is_noninheritable(svn_mergeinfo_t mergeinfo,
return FALSE;
}
-svn_error_t *
-svn_mergeinfo__string_has_noninheritable(svn_boolean_t *is_noninheritable,
- const char *mergeinfo_str,
- apr_pool_t *scratch_pool)
-{
- *is_noninheritable = FALSE;
-
- if (mergeinfo_str)
- {
- svn_mergeinfo_t mergeinfo;
-
- SVN_ERR(svn_mergeinfo_parse(&mergeinfo, mergeinfo_str, scratch_pool));
- *is_noninheritable = svn_mergeinfo__is_noninheritable(mergeinfo,
- scratch_pool);
- }
-
- return SVN_NO_ERROR;
-}
-
-apr_array_header_t *
+svn_rangelist_t *
svn_rangelist__initialize(svn_revnum_t start,
svn_revnum_t end,
svn_boolean_t inheritable,
apr_pool_t *result_pool)
{
- apr_array_header_t *rangelist =
+ svn_rangelist_t *rangelist =
apr_array_make(result_pool, 1, sizeof(svn_merge_range_t *));
svn_merge_range_t *range = apr_pcalloc(result_pool, sizeof(*range));
@@ -2571,7 +2591,7 @@ svn_mergeinfo__mergeinfo_from_segments(svn_mergeinfo_t *mergeinfo_p,
{
svn_location_segment_t *segment =
APR_ARRAY_IDX(segments, i, svn_location_segment_t *);
- apr_array_header_t *path_ranges;
+ svn_rangelist_t *path_ranges;
svn_merge_range_t *range;
const char *source_path;
@@ -2584,7 +2604,7 @@ svn_mergeinfo__mergeinfo_from_segments(svn_mergeinfo_t *mergeinfo_p,
/* See if we already stored ranges for this path. If not, make
a new list. */
- path_ranges = apr_hash_get(mergeinfo, source_path, APR_HASH_KEY_STRING);
+ path_ranges = svn_hash_gets(mergeinfo, source_path);
if (! path_ranges)
path_ranges = apr_array_make(pool, 1, sizeof(range));
@@ -2601,9 +2621,60 @@ svn_mergeinfo__mergeinfo_from_segments(svn_mergeinfo_t *mergeinfo_p,
range->end = segment->range_end;
range->inheritable = TRUE;
APR_ARRAY_PUSH(path_ranges, svn_merge_range_t *) = range;
- apr_hash_set(mergeinfo, source_path, APR_HASH_KEY_STRING, path_ranges);
+ svn_hash_sets(mergeinfo, source_path, path_ranges);
}
*mergeinfo_p = mergeinfo;
return SVN_NO_ERROR;
}
+
+svn_error_t *
+svn_rangelist__merge_many(svn_rangelist_t *merged_rangelist,
+ svn_mergeinfo_t merge_history,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ if (apr_hash_count(merge_history))
+ {
+ apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+ apr_hash_index_t *hi;
+
+ for (hi = apr_hash_first(scratch_pool, merge_history);
+ hi;
+ hi = apr_hash_next(hi))
+ {
+ svn_rangelist_t *subtree_rangelist = svn__apr_hash_index_val(hi);
+
+ svn_pool_clear(iterpool);
+ SVN_ERR(svn_rangelist_merge2(merged_rangelist, subtree_rangelist,
+ result_pool, iterpool));
+ }
+ svn_pool_destroy(iterpool);
+ }
+ return SVN_NO_ERROR;
+}
+
+
+const char *
+svn_inheritance_to_word(svn_mergeinfo_inheritance_t inherit)
+{
+ switch (inherit)
+ {
+ case svn_mergeinfo_inherited:
+ return "inherited";
+ case svn_mergeinfo_nearest_ancestor:
+ return "nearest-ancestor";
+ default:
+ return "explicit";
+ }
+}
+
+svn_mergeinfo_inheritance_t
+svn_inheritance_from_word(const char *word)
+{
+ if (strcmp(word, "inherited") == 0)
+ return svn_mergeinfo_inherited;
+ if (strcmp(word, "nearest-ancestor") == 0)
+ return svn_mergeinfo_nearest_ancestor;
+ return svn_mergeinfo_explicit;
+}