Alien-SVN
view release on metacpan or search on metacpan
src/subversion/subversion/libsvn_subr/mergeinfo.c view on Meta::CPAN
const svn_merge_range_t *in2,
svn_boolean_t consider_inheritance)
{
if (in1->start <= in2->end && in2->start <= in1->end)
{
if (!consider_inheritance
|| (consider_inheritance
&& (in1->inheritable == in2->inheritable)))
{
output->start = MIN(in1->start, in2->start);
output->end = MAX(in1->end, in2->end);
output->inheritable = (in1->inheritable || in2->inheritable);
return TRUE;
}
}
return FALSE;
}
/* pathname -> PATHNAME */
static svn_error_t *
parse_pathname(const char **input,
const char *end,
const char **pathname,
apr_pool_t *pool)
{
const char *curr = *input;
const char *last_colon = NULL;
/* A pathname may contain colons, so find the last colon before END
or newline. We'll consider this the divider between the pathname
and the revisionlist. */
while (curr < end && *curr != '\n')
{
if (*curr == ':')
last_colon = curr;
curr++;
}
if (!last_colon)
return svn_error_create(SVN_ERR_MERGEINFO_PARSE_ERROR, NULL,
_("Pathname not terminated by ':'"));
if (last_colon == *input)
return svn_error_create(SVN_ERR_MERGEINFO_PARSE_ERROR, NULL,
_("No pathname preceding ':'"));
/* Tolerate relative repository paths, but convert them to absolute.
### Efficiency? 1 string duplication here, 2 in canonicalize. */
*pathname = svn_fspath__canonicalize(apr_pstrndup(pool, *input,
last_colon - *input),
pool);
*input = last_colon;
return SVN_NO_ERROR;
}
/* Return TRUE iff (svn_merge_range_t *) RANGE describes a valid, forward
* revision range.
*
* Note: The smallest valid value of RANGE->start is 0 because it is an
* exclusive endpoint, being one less than the revision number of the first
* change described by the range, and the oldest possible change is "r1" as
* there cannot be a change "r0". */
#define IS_VALID_FORWARD_RANGE(range) \
(SVN_IS_VALID_REVNUM((range)->start) && ((range)->start < (range)->end))
/* Ways in which two svn_merge_range_t can intersect or adjoin, if at all. */
typedef enum intersection_type_t
{
/* Ranges don't intersect and don't adjoin. */
svn__no_intersection,
/* Ranges are equal. */
svn__equal_intersection,
/* Ranges adjoin but don't overlap. */
svn__adjoining_intersection,
/* Ranges overlap but neither is a subset of the other. */
svn__overlapping_intersection,
/* One range is a proper subset of the other. */
svn__proper_subset_intersection
} intersection_type_t;
/* Given ranges R1 and R2, both of which must be forward merge ranges,
set *INTERSECTION_TYPE to describe how the ranges intersect, if they
do at all. The inheritance type of the ranges is not considered. */
static svn_error_t *
get_type_of_intersection(const svn_merge_range_t *r1,
const svn_merge_range_t *r2,
intersection_type_t *intersection_type)
{
SVN_ERR_ASSERT(r1);
SVN_ERR_ASSERT(r2);
SVN_ERR_ASSERT(IS_VALID_FORWARD_RANGE(r1));
SVN_ERR_ASSERT(IS_VALID_FORWARD_RANGE(r2));
if (!(r1->start <= r2->end && r2->start <= r1->end))
*intersection_type = svn__no_intersection;
else if (r1->start == r2->start && r1->end == r2->end)
*intersection_type = svn__equal_intersection;
else if (r1->end == r2->start || r2->end == r1->start)
*intersection_type = svn__adjoining_intersection;
else if (r1->start <= r2->start && r1->end >= r2->end)
*intersection_type = svn__proper_subset_intersection;
else if (r2->start <= r1->start && r2->end >= r1->end)
*intersection_type = svn__proper_subset_intersection;
else
*intersection_type = svn__overlapping_intersection;
return SVN_NO_ERROR;
}
/* Modify or extend RANGELIST (a list of merge ranges) to incorporate
NEW_RANGE. RANGELIST is a "rangelist" as defined in svn_mergeinfo.h.
OVERVIEW
Determine the minimal set of non-overlapping merge ranges required to
represent the combination of RANGELIST and NEW_RANGE. The result depends
src/subversion/subversion/libsvn_subr/mergeinfo.c view on Meta::CPAN
RANGELIST and then set RANGE to the non-intersecting
portion of RANGE. */
svn_merge_range_t *range_copy =
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++);
j++;
}
}
}
}
}
/* 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,
result_pool);
svn_sort__array_insert(&change_copy, rangelist, rangelist->nelts);
}
return SVN_NO_ERROR;
}
/* Return TRUE iff the forward revision ranges FIRST and SECOND overlap and
* (if CONSIDER_INHERITANCE is TRUE) have the same inheritability. */
static svn_boolean_t
range_intersect(const svn_merge_range_t *first, const svn_merge_range_t *second,
svn_boolean_t consider_inheritance)
{
SVN_ERR_ASSERT_NO_RETURN(IS_VALID_FORWARD_RANGE(first));
SVN_ERR_ASSERT_NO_RETURN(IS_VALID_FORWARD_RANGE(second));
return (first->start + 1 <= second->end)
&& (second->start + 1 <= first->end)
&& (!consider_inheritance
|| (!(first->inheritable) == !(second->inheritable)));
}
/* Return TRUE iff the forward revision range FIRST wholly contains the
* forward revision range SECOND and (if CONSIDER_INHERITANCE is TRUE) has
* the same inheritability. */
static svn_boolean_t
range_contains(const svn_merge_range_t *first, const svn_merge_range_t *second,
svn_boolean_t consider_inheritance)
{
SVN_ERR_ASSERT_NO_RETURN(IS_VALID_FORWARD_RANGE(first));
SVN_ERR_ASSERT_NO_RETURN(IS_VALID_FORWARD_RANGE(second));
return (first->start <= second->start) && (second->end <= first->end)
&& (!consider_inheritance
|| (!(first->inheritable) == !(second->inheritable)));
}
/* Swap start and end fields of RANGE. */
static void
range_swap_endpoints(svn_merge_range_t *range)
{
svn_revnum_t swap = range->start;
range->start = range->end;
range->end = swap;
}
svn_error_t *
svn_rangelist_reverse(svn_rangelist_t *rangelist, apr_pool_t *pool)
{
int i;
svn_sort__array_reverse(rangelist, pool);
for (i = 0; i < rangelist->nelts; i++)
{
range_swap_endpoints(APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *));
}
return SVN_NO_ERROR;
}
void
svn_rangelist__set_inheritance(svn_rangelist_t *rangelist,
svn_boolean_t inheritable)
{
if (rangelist)
{
int i;
svn_merge_range_t *range;
for (i = 0; i < rangelist->nelts; i++)
{
range = APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *);
range->inheritable = inheritable;
}
}
return;
}
void
svn_mergeinfo__set_inheritance(svn_mergeinfo_t mergeinfo,
svn_boolean_t inheritable,
apr_pool_t *scratch_pool)
{
if (mergeinfo)
{
apr_hash_index_t *hi;
for (hi = apr_hash_first(scratch_pool, mergeinfo);
hi;
hi = apr_hash_next(hi))
{
svn_rangelist_t *rangelist = svn__apr_hash_index_val(hi);
if (rangelist)
svn_rangelist__set_inheritance(rangelist, inheritable);
}
}
return;
}
/* If DO_REMOVE is true, then remove any overlapping ranges described by
RANGELIST1 from RANGELIST2 and place the results in *OUTPUT. When
DO_REMOVE is true, RANGELIST1 is effectively the "eraser" and RANGELIST2
the "whiteboard".
If DO_REMOVE is false, then capture the intersection between RANGELIST1
and RANGELIST2 and place the results in *OUTPUT. The ordering of
RANGELIST1 and RANGELIST2 doesn't matter when DO_REMOVE is false.
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_intersect().
If CONSIDER_INHERITANCE is false, then ranges with differing inheritance
may intersect, but the resulting intersection is non-inheritable only
src/subversion/subversion/libsvn_subr/mergeinfo.c view on Meta::CPAN
svn_mergeinfo__catalog_to_formatted_string(svn_string_t **output,
svn_mergeinfo_catalog_t catalog,
const char *key_prefix,
const char *val_prefix,
apr_pool_t *pool)
{
svn_stringbuf_t *output_buf = NULL;
if (catalog && apr_hash_count(catalog))
{
int i;
apr_array_header_t *sorted_catalog =
svn_sort__hash(catalog, svn_sort_compare_items_as_paths, pool);
output_buf = svn_stringbuf_create_empty(pool);
for (i = 0; i < sorted_catalog->nelts; i++)
{
svn_sort__item_t elt =
APR_ARRAY_IDX(sorted_catalog, i, svn_sort__item_t);
const char *path1;
svn_mergeinfo_t mergeinfo;
svn_stringbuf_t *mergeinfo_output_buf;
path1 = elt.key;
mergeinfo = elt.value;
if (key_prefix)
svn_stringbuf_appendcstr(output_buf, key_prefix);
svn_stringbuf_appendcstr(output_buf, path1);
svn_stringbuf_appendcstr(output_buf, "\n");
SVN_ERR(mergeinfo_to_stringbuf(&mergeinfo_output_buf, mergeinfo,
val_prefix ? val_prefix : "", pool));
svn_stringbuf_appendstr(output_buf, mergeinfo_output_buf);
svn_stringbuf_appendcstr(output_buf, "\n");
}
}
#if SVN_DEBUG
else if (!catalog)
{
output_buf = svn_stringbuf_create(key_prefix ? key_prefix : "", pool);
svn_stringbuf_appendcstr(output_buf, _("NULL mergeinfo catalog\n"));
}
else if (apr_hash_count(catalog) == 0)
{
output_buf = svn_stringbuf_create(key_prefix ? key_prefix : "", pool);
svn_stringbuf_appendcstr(output_buf, _("empty mergeinfo catalog\n"));
}
#endif
/* If we have an output_buf, convert it to an svn_string_t;
otherwise, return a new string containing only a newline
character. */
if (output_buf)
*output = svn_stringbuf__morph_into_string(output_buf);
else
*output = svn_string_create("\n", 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,
apr_pool_t *pool)
{
*youngest_rev = *oldest_rev = SVN_INVALID_REVNUM;
if (mergeinfo)
{
apr_hash_index_t *hi;
for (hi = apr_hash_first(pool, mergeinfo); hi; hi = apr_hash_next(hi))
{
svn_rangelist_t *rangelist = svn__apr_hash_index_val(hi);
if (rangelist->nelts)
{
svn_merge_range_t *range = APR_ARRAY_IDX(rangelist,
rangelist->nelts - 1,
svn_merge_range_t *);
if (!SVN_IS_VALID_REVNUM(*youngest_rev)
|| (range->end > *youngest_rev))
*youngest_rev = range->end;
range = APR_ARRAY_IDX(rangelist, 0, svn_merge_range_t *);
if (!SVN_IS_VALID_REVNUM(*oldest_rev)
|| (range->start < *oldest_rev))
*oldest_rev = range->start;
}
}
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_mergeinfo__filter_catalog_by_ranges(svn_mergeinfo_catalog_t *filtered_cat,
svn_mergeinfo_catalog_t catalog,
svn_revnum_t youngest_rev,
svn_revnum_t oldest_rev,
svn_boolean_t include_range,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
apr_hash_index_t *hi;
*filtered_cat = apr_hash_make(result_pool);
for (hi = apr_hash_first(scratch_pool, catalog);
hi;
hi = apr_hash_next(hi))
{
const char *path = svn__apr_hash_index_key(hi);
svn_mergeinfo_t mergeinfo = svn__apr_hash_index_val(hi);
svn_mergeinfo_t filtered_mergeinfo;
SVN_ERR(svn_mergeinfo__filter_mergeinfo_by_ranges(&filtered_mergeinfo,
mergeinfo,
youngest_rev,
oldest_rev,
include_range,
result_pool,
scratch_pool));
if (apr_hash_count(filtered_mergeinfo))
( run in 0.993 second using v1.01-cache-2.11-cpan-524268b4103 )