~ubuntu-branches/debian/sid/subversion/sid

« back to all changes in this revision

Viewing changes to subversion/libsvn_subr/mergeinfo.c

  • Committer: Package Import Robot
  • Author(s): James McCoy, Peter Samuelson, James McCoy
  • Date: 2014-01-12 19:48:33 UTC
  • mfrom: (0.2.10)
  • Revision ID: package-import@ubuntu.com-20140112194833-w3axfwksn296jn5x
Tags: 1.8.5-1
[ Peter Samuelson ]
* New upstream release.  (Closes: #725787) Rediff patches:
  - Remove apr-abi1 (applied upstream), rename apr-abi2 to apr-abi
  - Remove loosen-sqlite-version-check (shouldn't be needed)
  - Remove java-osgi-metadata (applied upstream)
  - svnmucc prompts for a changelog if none is provided. (Closes: #507430)
  - Remove fix-bdb-version-detection, upstream uses "apu-config --dbm-libs"
  - Remove ruby-test-wc (applied upstream)
  - Fix “svn diff -r N file” when file has svn:mime-type set.
    (Closes: #734163)
  - Support specifying an encoding for mod_dav_svn's environment in which
    hooks are run.  (Closes: #601544)
  - Fix ordering of “svnadmin dump” paths with certain APR versions.
    (Closes: #687291)
  - Provide a better error message when authentication fails with an
    svn+ssh:// URL.  (Closes: #273874)
  - Updated Polish translations.  (Closes: #690815)

[ James McCoy ]
* Remove all traces of libneon, replaced by libserf.
* patches/sqlite_3.8.x_workaround: Upstream fix for wc-queries-test test
  failurse.
* Run configure with --with-apache-libexecdir, which allows removing part of
  patches/rpath.
* Re-enable auth-test as upstream has fixed the problem of picking up
  libraries from the environment rather than the build tree.
  (Closes: #654172)
* Point LD_LIBRARY_PATH at the built auth libraries when running the svn
  command during the build.  (Closes: #678224)
* Add a NEWS entry describing how to configure mod_dav_svn to understand
  UTF-8.  (Closes: #566148)
* Remove ancient transitional package, libsvn-ruby.
* Enable compatibility with Sqlite3 versions back to Wheezy.
* Enable hardening flags.  (Closes: #734918)
* patches/build-fixes: Enable verbose build logs.
* Build against the default ruby version.  (Closes: #722393)

Show diffs side-by-side

added added

removed removed

Lines of Context:
35
35
#include "private/svn_fspath.h"
36
36
#include "private/svn_mergeinfo_private.h"
37
37
#include "private/svn_string_private.h"
 
38
#include "private/svn_subr_private.h"
38
39
#include "svn_private_config.h"
39
40
#include "svn_hash.h"
 
41
#include "private/svn_dep_compat.h"
40
42
 
41
43
/* Attempt to combine two ranges, IN1 and IN2. If they are adjacent or
42
44
   overlapping, and their inheritability allows them to be combined, put
238
240
 
239
241
   When replacing the last range in RANGELIST, either allocate a new range in
240
242
   RESULT_POOL or modify the existing range in place.  Any new ranges added
241
 
   to RANGELIST are allocated in RESULT_POOL.  SCRATCH_POOL is used for any
242
 
   temporary allocations.
 
243
   to RANGELIST are allocated in RESULT_POOL.
243
244
*/
244
245
static svn_error_t *
245
246
combine_with_lastrange(const svn_merge_range_t *new_range,
246
 
                       apr_array_header_t *rangelist,
 
247
                       svn_rangelist_t *rangelist,
247
248
                       svn_boolean_t consider_inheritance,
248
 
                       apr_pool_t *result_pool,
249
 
                       apr_pool_t *scratch_pool)
 
249
                       apr_pool_t *result_pool)
250
250
{
251
251
  svn_merge_range_t *lastrange;
252
252
  svn_merge_range_t combined_range;
299
299
          SVN_ERR(get_type_of_intersection(new_range, lastrange,
300
300
                                           &intersection_type));
301
301
 
302
 
              switch (intersection_type)
303
 
                {
304
 
                  case svn__no_intersection:
305
 
                    /* NEW_RANGE and *LASTRANGE *really* don't intersect so
306
 
                       just push NEW_RANGE only RANGELIST. */
307
 
                    APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) =
308
 
                      svn_merge_range_dup(new_range, result_pool);
309
 
                    sorted = (svn_sort_compare_ranges(&lastrange,
310
 
                                                      &new_range) < 0);
311
 
                    break;
312
 
 
313
 
                  case svn__equal_intersection:
314
 
                    /* They range are equal so all we do is force the
315
 
                       inheritability of lastrange to true. */
316
 
                    lastrange->inheritable = TRUE;
317
 
                    sorted = TRUE;
318
 
                    break;
319
 
 
320
 
                  case svn__adjoining_intersection:
321
 
                    /* They adjoin but don't overlap so just push NEW_RANGE
322
 
                       onto RANGELIST. */
323
 
                    APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) =
324
 
                      svn_merge_range_dup(new_range, result_pool);
325
 
                    sorted = (svn_sort_compare_ranges(&lastrange,
326
 
                                                      &new_range) < 0);
327
 
                    break;
328
 
 
329
 
                  case svn__overlapping_intersection:
330
 
                    /* They ranges overlap but neither is a proper subset of
331
 
                       the other.  We'll end up pusing two new ranges onto
332
 
                       RANGELIST, the intersecting part and the part unique to
333
 
                       NEW_RANGE.*/
334
 
                    {
335
 
                      svn_merge_range_t *r1 = svn_merge_range_dup(lastrange,
336
 
                                                                  result_pool);
337
 
                      svn_merge_range_t *r2 = svn_merge_range_dup(new_range,
338
 
                                                                  result_pool);
339
 
 
340
 
                      /* Pop off *LASTRANGE to make our manipulations
341
 
                         easier. */
342
 
                      apr_array_pop(rangelist);
343
 
 
344
 
                      /* Ensure R1 is the older range. */
345
 
                      if (r2->start < r1->start)
346
 
                        {
347
 
                          /* Swap R1 and R2. */
348
 
                          *r2 = *r1;
349
 
                          *r1 = *new_range;
350
 
                        }
351
 
 
352
 
                      /* Absorb the intersecting ranges into the
353
 
                         inheritable range. */
354
 
                      if (r1->inheritable)
355
 
                        r2->start = r1->end;
356
 
                      else
357
 
                        r1->end = r2->start;
358
 
 
359
 
                      /* Push everything back onto RANGELIST. */
360
 
                      APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) = r1;
361
 
                      sorted = (svn_sort_compare_ranges(&lastrange,
362
 
                                                        &r1) < 0);
 
302
          switch (intersection_type)
 
303
            {
 
304
              case svn__no_intersection:
 
305
                /* NEW_RANGE and *LASTRANGE *really* don't intersect so
 
306
                   just push NEW_RANGE only RANGELIST. */
 
307
                APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) =
 
308
                  svn_merge_range_dup(new_range, result_pool);
 
309
                sorted = (svn_sort_compare_ranges(&lastrange,
 
310
                                                  &new_range) < 0);
 
311
                break;
 
312
 
 
313
              case svn__equal_intersection:
 
314
                /* They range are equal so all we do is force the
 
315
                   inheritability of lastrange to true. */
 
316
                lastrange->inheritable = TRUE;
 
317
                sorted = TRUE;
 
318
                break;
 
319
 
 
320
              case svn__adjoining_intersection:
 
321
                /* They adjoin but don't overlap so just push NEW_RANGE
 
322
                   onto RANGELIST. */
 
323
                APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) =
 
324
                  svn_merge_range_dup(new_range, result_pool);
 
325
                sorted = (svn_sort_compare_ranges(&lastrange,
 
326
                                                  &new_range) < 0);
 
327
                break;
 
328
 
 
329
              case svn__overlapping_intersection:
 
330
                /* They ranges overlap but neither is a proper subset of
 
331
                   the other.  We'll end up pusing two new ranges onto
 
332
                   RANGELIST, the intersecting part and the part unique to
 
333
                   NEW_RANGE.*/
 
334
                {
 
335
                  svn_merge_range_t *r1 = svn_merge_range_dup(lastrange,
 
336
                                                              result_pool);
 
337
                  svn_merge_range_t *r2 = svn_merge_range_dup(new_range,
 
338
                                                              result_pool);
 
339
 
 
340
                  /* Pop off *LASTRANGE to make our manipulations
 
341
                     easier. */
 
342
                  apr_array_pop(rangelist);
 
343
 
 
344
                  /* Ensure R1 is the older range. */
 
345
                  if (r2->start < r1->start)
 
346
                    {
 
347
                      /* Swap R1 and R2. */
 
348
                      *r2 = *r1;
 
349
                      *r1 = *new_range;
 
350
                    }
 
351
 
 
352
                  /* Absorb the intersecting ranges into the
 
353
                     inheritable range. */
 
354
                  if (r1->inheritable)
 
355
                    r2->start = r1->end;
 
356
                  else
 
357
                    r1->end = r2->start;
 
358
 
 
359
                  /* Push everything back onto RANGELIST. */
 
360
                  APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) = r1;
 
361
                  sorted = (svn_sort_compare_ranges(&lastrange,
 
362
                                                    &r1) < 0);
 
363
                  APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) = r2;
 
364
                  if (sorted)
 
365
                    sorted = (svn_sort_compare_ranges(&r1, &r2) < 0);
 
366
                  break;
 
367
                }
 
368
 
 
369
              default: /* svn__proper_subset_intersection */
 
370
                {
 
371
                  /* One range is a proper subset of the other. */
 
372
                  svn_merge_range_t *r1 = svn_merge_range_dup(lastrange,
 
373
                                                              result_pool);
 
374
                  svn_merge_range_t *r2 = svn_merge_range_dup(new_range,
 
375
                                                              result_pool);
 
376
                  svn_merge_range_t *r3 = NULL;
 
377
 
 
378
                  /* Pop off *LASTRANGE to make our manipulations
 
379
                     easier. */
 
380
                  apr_array_pop(rangelist);
 
381
 
 
382
                  /* Ensure R1 is the superset. */
 
383
                  if (r2->start < r1->start || r2->end > r1->end)
 
384
                    {
 
385
                      /* Swap R1 and R2. */
 
386
                      *r2 = *r1;
 
387
                      *r1 = *new_range;
 
388
                    }
 
389
 
 
390
                  if (r1->inheritable)
 
391
                    {
 
392
                      /* The simple case: The superset is inheritable, so
 
393
                         just combine r1 and r2. */
 
394
                      r1->start = MIN(r1->start, r2->start);
 
395
                      r1->end = MAX(r1->end, r2->end);
 
396
                      r2 = NULL;
 
397
                    }
 
398
                  else if (r1->start == r2->start)
 
399
                    {
 
400
                      svn_revnum_t tmp_revnum;
 
401
 
 
402
                      /* *LASTRANGE and NEW_RANGE share an end point. */
 
403
                      tmp_revnum = r1->end;
 
404
                      r1->end = r2->end;
 
405
                      r2->inheritable = r1->inheritable;
 
406
                      r1->inheritable = TRUE;
 
407
                      r2->start = r1->end;
 
408
                      r2->end = tmp_revnum;
 
409
                    }
 
410
                  else if (r1->end == r2->end)
 
411
                    {
 
412
                      /* *LASTRANGE and NEW_RANGE share an end point. */
 
413
                      r1->end = r2->start;
 
414
                      r2->inheritable = TRUE;
 
415
                    }
 
416
                  else
 
417
                    {
 
418
                      /* NEW_RANGE and *LASTRANGE share neither start
 
419
                         nor end points. */
 
420
                      r3 = apr_pcalloc(result_pool, sizeof(*r3));
 
421
                      r3->start = r2->end;
 
422
                      r3->end = r1->end;
 
423
                      r3->inheritable = r1->inheritable;
 
424
                      r2->inheritable = TRUE;
 
425
                      r1->end = r2->start;
 
426
                    }
 
427
 
 
428
                  /* Push everything back onto RANGELIST. */
 
429
                  APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) = r1;
 
430
                  sorted = (svn_sort_compare_ranges(&lastrange, &r1) < 0);
 
431
                  if (r2)
 
432
                    {
363
433
                      APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) = r2;
364
434
                      if (sorted)
365
435
                        sorted = (svn_sort_compare_ranges(&r1, &r2) < 0);
366
 
                      break;
367
436
                    }
368
 
 
369
 
                  default: /* svn__proper_subset_intersection */
 
437
                  if (r3)
370
438
                    {
371
 
                      /* One range is a proper subset of the other. */
372
 
                      svn_merge_range_t *r1 = svn_merge_range_dup(lastrange,
373
 
                                                                  result_pool);
374
 
                      svn_merge_range_t *r2 = svn_merge_range_dup(new_range,
375
 
                                                                  result_pool);
376
 
                      svn_merge_range_t *r3 = NULL;
377
 
 
378
 
                      /* Pop off *LASTRANGE to make our manipulations
379
 
                         easier. */
380
 
                      apr_array_pop(rangelist);
381
 
 
382
 
                      /* Ensure R1 is the superset. */
383
 
                      if (r2->start < r1->start || r2->end > r1->end)
384
 
                        {
385
 
                          /* Swap R1 and R2. */
386
 
                          *r2 = *r1;
387
 
                          *r1 = *new_range;
388
 
                        }
389
 
 
390
 
                      if (r1->inheritable)
391
 
                        {
392
 
                          /* The simple case: The superset is inheritable, so
393
 
                             just combine r1 and r2. */
394
 
                          r1->start = MIN(r1->start, r2->start);
395
 
                          r1->end = MAX(r1->end, r2->end);
396
 
                          r2 = NULL;
397
 
                        }
398
 
                      else if (r1->start == r2->start)
399
 
                        {
400
 
                          svn_revnum_t tmp_revnum;
401
 
 
402
 
                          /* *LASTRANGE and NEW_RANGE share an end point. */
403
 
                          tmp_revnum = r1->end;
404
 
                          r1->end = r2->end;
405
 
                          r2->inheritable = r1->inheritable;
406
 
                          r1->inheritable = TRUE;
407
 
                          r2->start = r1->end;
408
 
                          r2->end = tmp_revnum;
409
 
                        }
410
 
                      else if (r1->end == r2->end)
411
 
                        {
412
 
                          /* *LASTRANGE and NEW_RANGE share an end point. */
413
 
                          r1->end = r2->start;
414
 
                          r2->inheritable = TRUE;
415
 
                        }
416
 
                      else
417
 
                        {
418
 
                          /* NEW_RANGE and *LASTRANGE share neither start
419
 
                             nor end points. */
420
 
                          r3 = apr_pcalloc(result_pool, sizeof(*r3));
421
 
                          r3->start = r2->end;
422
 
                          r3->end = r1->end;
423
 
                          r3->inheritable = r1->inheritable;
424
 
                          r2->inheritable = TRUE;
425
 
                          r1->end = r2->start;
426
 
                        }
427
 
 
428
 
                      /* Push everything back onto RANGELIST. */
429
 
                      APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) = r1;
430
 
                      sorted = (svn_sort_compare_ranges(&lastrange, &r1) < 0);
431
 
                      if (r2)
432
 
                        {
433
 
                          APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) = r2;
434
 
                          if (sorted)
435
 
                            sorted = (svn_sort_compare_ranges(&r1, &r2) < 0);
436
 
                        }
437
 
                      if (r3)
438
 
                        {
439
 
                          APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) = r3;
440
 
                          if (sorted)
441
 
                            {
442
 
                              if (r2)
443
 
                                sorted = (svn_sort_compare_ranges(&r2,
444
 
                                                                  &r3) < 0);
445
 
                              else
446
 
                                sorted = (svn_sort_compare_ranges(&r1,
447
 
                                                                  &r3) < 0);
448
 
                            }
449
 
                        }
450
 
                      break;
 
439
                      APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) = r3;
 
440
                      if (sorted)
 
441
                        {
 
442
                          if (r2)
 
443
                            sorted = (svn_sort_compare_ranges(&r2,
 
444
                                                              &r3) < 0);
 
445
                          else
 
446
                            sorted = (svn_sort_compare_ranges(&r1,
 
447
                                                              &r3) < 0);
 
448
                        }
451
449
                    }
 
450
                  break;
452
451
                }
 
452
            }
453
453
 
454
 
              /* Some of the above cases might have put *RANGELIST out of
455
 
                 order, so re-sort.*/
456
 
              if (!sorted)
457
 
                qsort(rangelist->elts, rangelist->nelts, rangelist->elt_size,
458
 
                      svn_sort_compare_ranges);
 
454
          /* Some of the above cases might have put *RANGELIST out of
 
455
             order, so re-sort.*/
 
456
          if (!sorted)
 
457
            qsort(rangelist->elts, rangelist->nelts, rangelist->elt_size,
 
458
                  svn_sort_compare_ranges);
459
459
        }
460
460
    }
461
461
 
489
489
   revisionlist -> (revisionelement)(COMMA revisionelement)*
490
490
   revisionrange -> REVISION "-" REVISION("*")
491
491
   revisionelement -> revisionrange | REVISION("*")
492
 
 
493
 
   PATHNAME is the path this revisionlist is mapped to.  It is
494
 
   used only for producing a more descriptive error message.
495
492
*/
496
493
static svn_error_t *
497
494
parse_rangelist(const char **input, const char *end,
498
 
                apr_array_header_t *rangelist, const char *pathname,
 
495
                svn_rangelist_t *rangelist,
499
496
                apr_pool_t *pool)
500
497
{
501
498
  const char *curr = *input;
508
505
    {
509
506
      /* Empty range list. */
510
507
      *input = curr;
511
 
      return svn_error_createf(SVN_ERR_MERGEINFO_PARSE_ERROR, NULL,
512
 
                               _("Mergeinfo for '%s' maps to an "
513
 
                                 "empty revision range"), pathname);
 
508
      return SVN_NO_ERROR;
514
509
    }
515
510
 
516
511
  while (curr < end && *curr != '\n')
604
599
  return SVN_NO_ERROR;
605
600
}
606
601
 
 
602
svn_error_t *
 
603
svn_rangelist__parse(svn_rangelist_t **rangelist,
 
604
                     const char *str,
 
605
                     apr_pool_t *result_pool)
 
606
{
 
607
  const char *s = str;
 
608
 
 
609
  *rangelist = apr_array_make(result_pool, 1, sizeof(svn_merge_range_t *));
 
610
  SVN_ERR(parse_rangelist(&s, s + strlen(s), *rangelist, result_pool));
 
611
  return SVN_NO_ERROR;
 
612
}
 
613
 
 
614
svn_error_t *
 
615
svn_rangelist__combine_adjacent_ranges(svn_rangelist_t *rangelist,
 
616
                                       apr_pool_t *scratch_pool)
 
617
{
 
618
  int i;
 
619
  svn_merge_range_t *range, *lastrange;
 
620
 
 
621
  lastrange = APR_ARRAY_IDX(rangelist, 0, svn_merge_range_t *);
 
622
 
 
623
  for (i = 1; i < rangelist->nelts; i++)
 
624
    {
 
625
      range = APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *);
 
626
      if (lastrange->start <= range->end
 
627
          && range->start <= lastrange->end)
 
628
        {
 
629
          /* The ranges are adjacent or intersect. */
 
630
 
 
631
          /* svn_mergeinfo_parse promises to combine overlapping
 
632
             ranges as long as their inheritability is the same. */
 
633
          if (range->start < lastrange->end
 
634
              && range->inheritable != lastrange->inheritable)
 
635
            {
 
636
              return svn_error_createf(SVN_ERR_MERGEINFO_PARSE_ERROR, NULL,
 
637
                                       _("Unable to parse overlapping "
 
638
                                         "revision ranges '%s' and '%s' "
 
639
                                         "with different inheritance "
 
640
                                         "types"),
 
641
                                       range_to_string(lastrange,
 
642
                                                       scratch_pool),
 
643
                                       range_to_string(range,
 
644
                                                       scratch_pool));
 
645
            }
 
646
 
 
647
          /* Combine overlapping or adjacent ranges with the
 
648
             same inheritability. */
 
649
          if (lastrange->inheritable == range->inheritable)
 
650
            {
 
651
              lastrange->end = MAX(range->end, lastrange->end);
 
652
              svn_sort__array_delete(rangelist, i, 1);
 
653
              i--;
 
654
            }
 
655
        }
 
656
      lastrange = APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *);
 
657
    }
 
658
 
 
659
  return SVN_NO_ERROR;
 
660
}
 
661
 
607
662
/* revisionline -> PATHNAME COLON revisionlist */
608
663
static svn_error_t *
609
664
parse_revision_line(const char **input, const char *end, svn_mergeinfo_t hash,
610
 
                    apr_pool_t *pool)
 
665
                    apr_pool_t *scratch_pool)
611
666
{
612
 
  const char *pathname;
613
 
  apr_array_header_t *existing_rangelist;
614
 
  apr_array_header_t *rangelist = apr_array_make(pool, 1,
615
 
                                                 sizeof(svn_merge_range_t *));
 
667
  const char *pathname = "";
 
668
  apr_ssize_t klen;
 
669
  svn_rangelist_t *existing_rangelist;
 
670
  svn_rangelist_t *rangelist = apr_array_make(scratch_pool, 1,
 
671
                                              sizeof(svn_merge_range_t *));
616
672
 
617
 
  SVN_ERR(parse_pathname(input, end, &pathname, pool));
 
673
  SVN_ERR(parse_pathname(input, end, &pathname, scratch_pool));
618
674
 
619
675
  if (*(*input) != ':')
620
676
    return svn_error_create(SVN_ERR_MERGEINFO_PARSE_ERROR, NULL,
622
678
 
623
679
  *input = *input + 1;
624
680
 
625
 
  SVN_ERR(parse_rangelist(input, end, rangelist, pathname, pool));
 
681
  SVN_ERR(parse_rangelist(input, end, rangelist, scratch_pool));
626
682
 
 
683
  if (rangelist->nelts == 0)
 
684
      return svn_error_createf(SVN_ERR_MERGEINFO_PARSE_ERROR, NULL,
 
685
                               _("Mergeinfo for '%s' maps to an "
 
686
                                 "empty revision range"), pathname);
627
687
  if (*input != end && *(*input) != '\n')
628
688
    return svn_error_createf(SVN_ERR_MERGEINFO_PARSE_ERROR, NULL,
629
689
                             _("Could not find end of line in range list line "
636
696
     and make sure there are no overlapping ranges. */
637
697
  if (rangelist->nelts > 1)
638
698
    {
639
 
      int i;
640
 
      svn_merge_range_t *range, *lastrange;
641
 
 
642
699
      qsort(rangelist->elts, rangelist->nelts, rangelist->elt_size,
643
700
            svn_sort_compare_ranges);
644
 
      lastrange = APR_ARRAY_IDX(rangelist, 0, svn_merge_range_t *);
645
 
 
646
 
      for (i = 1; i < rangelist->nelts; i++)
647
 
        {
648
 
          range = APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *);
649
 
          if (lastrange->start <= range->end
650
 
              && range->start <= lastrange->end)
651
 
            {
652
 
              /* The ranges are adjacent or intersect. */
653
 
 
654
 
              /* svn_mergeinfo_parse promises to combine overlapping
655
 
                 ranges as long as their inheritability is the same. */
656
 
              if (range->start < lastrange->end
657
 
                  && range->inheritable != lastrange->inheritable)
658
 
                {
659
 
                  return svn_error_createf(SVN_ERR_MERGEINFO_PARSE_ERROR, NULL,
660
 
                                           _("Unable to parse overlapping "
661
 
                                             "revision ranges '%s' and '%s' "
662
 
                                             "with different inheritance "
663
 
                                             "types"),
664
 
                                           range_to_string(lastrange, pool),
665
 
                                           range_to_string(range, pool));
666
 
                }
667
 
 
668
 
              /* Combine overlapping or adjacent ranges with the
669
 
                 same inheritability. */
670
 
              if (lastrange->inheritable == range->inheritable)
671
 
                {
672
 
                  lastrange->end = MAX(range->end, lastrange->end);
673
 
                  if (i + 1 < rangelist->nelts)
674
 
                    memmove(rangelist->elts + (rangelist->elt_size * i),
675
 
                            rangelist->elts + (rangelist->elt_size * (i + 1)),
676
 
                            rangelist->elt_size * (rangelist->nelts - i));
677
 
                  rangelist->nelts--;
678
 
                  i--;
679
 
                }
680
 
            }
681
 
          lastrange = APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *);
682
 
        }
 
701
 
 
702
      SVN_ERR(svn_rangelist__combine_adjacent_ranges(rangelist, scratch_pool));
683
703
    }
684
704
 
685
705
  /* Handle any funky mergeinfo with relative merge source paths that
688
708
     leading slash, e.g. "trunk:4033\n/trunk:4039-4995".  In the event
689
709
     we encounter this we merge the rangelists together under a single
690
710
     absolute path key. */
691
 
  existing_rangelist = apr_hash_get(hash, pathname, APR_HASH_KEY_STRING);
 
711
  klen = strlen(pathname);
 
712
  existing_rangelist = apr_hash_get(hash, pathname, klen);
692
713
  if (existing_rangelist)
693
 
    SVN_ERR(svn_rangelist_merge(&rangelist, existing_rangelist, pool));
 
714
    SVN_ERR(svn_rangelist_merge2(rangelist, existing_rangelist,
 
715
                                 scratch_pool, scratch_pool));
694
716
 
695
 
  apr_hash_set(hash, pathname, APR_HASH_KEY_STRING, rangelist);
 
717
  apr_hash_set(hash, apr_pstrmemdup(apr_hash_pool_get(hash), pathname, klen),
 
718
               klen, svn_rangelist_dup(rangelist, apr_hash_pool_get(hash)));
696
719
 
697
720
  return SVN_NO_ERROR;
698
721
}
702
725
parse_top(const char **input, const char *end, svn_mergeinfo_t hash,
703
726
          apr_pool_t *pool)
704
727
{
 
728
  apr_pool_t *iterpool = svn_pool_create(pool);
 
729
 
705
730
  while (*input < end)
706
 
    SVN_ERR(parse_revision_line(input, end, hash, pool));
 
731
    {
 
732
      svn_pool_clear(iterpool);
 
733
      SVN_ERR(parse_revision_line(input, end, hash, iterpool));
 
734
    }
 
735
  svn_pool_destroy(iterpool);
707
736
 
708
737
  return SVN_NO_ERROR;
709
738
}
715
744
{
716
745
  svn_error_t *err;
717
746
 
718
 
  *mergeinfo = apr_hash_make(pool);
 
747
  *mergeinfo = svn_hash__make(pool);
719
748
  err = parse_top(&input, input + strlen(input), *mergeinfo, pool);
720
749
 
721
750
  /* Always return SVN_ERR_MERGEINFO_PARSE_ERROR as the topmost error. */
726
755
  return err;
727
756
}
728
757
 
729
 
/* Cleanup after svn_rangelist_merge when it modifies the ending range of
 
758
/* Cleanup after svn_rangelist_merge2 when it modifies the ending range of
730
759
   a single rangelist element in-place.
731
760
 
732
 
   If *INDEX is not a valid element in RANGELIST do nothing.  Otherwise ensure
733
 
   that RANGELIST[*INDEX]->END does not adjoin or overlap any subsequent
734
 
   ranges in RANGELIST.
 
761
   If *RANGE_INDEX is not a valid element in RANGELIST do nothing.  Otherwise
 
762
   ensure that RANGELIST[*RANGE_INDEX]->END does not adjoin or overlap any
 
763
   subsequent ranges in RANGELIST.
735
764
 
736
765
   If overlap is found, then remove, modify, and/or add elements to RANGELIST
737
766
   as per the invariants for rangelists documented in svn_mergeinfo.h.  If
738
 
   RANGELIST[*INDEX]->END adjoins a subsequent element then combine the
 
767
   RANGELIST[*RANGE_INDEX]->END adjoins a subsequent element then combine the
739
768
   elements if their inheritability permits -- The inheritance of intersecting
740
769
   and adjoining ranges is handled as per svn_mergeinfo_merge2.  Upon return
741
 
   set *INDEX to the index of the youngest element modified, added, or
742
 
   adjoined to RANGELIST[*INDEX].
 
770
   set *RANGE_INDEX to the index of the youngest element modified, added, or
 
771
   adjoined to RANGELIST[*RANGE_INDEX].
743
772
 
744
773
   Note: Adjoining rangelist elements are those where the end rev of the older
745
774
   element is equal to the start rev of the younger element.
746
775
 
747
776
   Any new elements inserted into RANGELIST are allocated in  RESULT_POOL.*/
748
777
static void
749
 
adjust_remaining_ranges(apr_array_header_t *rangelist,
750
 
                        int *index,
 
778
adjust_remaining_ranges(svn_rangelist_t *rangelist,
 
779
                        int *range_index,
751
780
                        apr_pool_t *result_pool)
752
781
{
753
782
  int i;
755
784
  int elements_to_delete = 0;
756
785
  svn_merge_range_t *modified_range;
757
786
 
758
 
  if (*index >= rangelist->nelts)
 
787
  if (*range_index >= rangelist->nelts)
759
788
    return;
760
789
 
761
 
  starting_index = *index + 1;
762
 
  modified_range = APR_ARRAY_IDX(rangelist, *index, svn_merge_range_t *);
 
790
  starting_index = *range_index + 1;
 
791
  modified_range = APR_ARRAY_IDX(rangelist, *range_index, svn_merge_range_t *);
763
792
 
764
 
  for (i = *index + 1; i < rangelist->nelts; i++)
 
793
  for (i = *range_index + 1; i < rangelist->nelts; i++)
765
794
    {
766
795
      svn_merge_range_t *next_range = APR_ARRAY_IDX(rangelist, i,
767
796
                                                    svn_merge_range_t *);
783
812
          else
784
813
            {
785
814
              /* Cannot join because inheritance differs. */
786
 
              (*index)++;
 
815
              (*range_index)++;
787
816
            }
788
817
          break;
789
818
        }
829
858
              new_modified_range->end = modified_range->end;
830
859
              new_modified_range->inheritable = FALSE;
831
860
              modified_range->end = next_range->start;
832
 
              (*index)+=2;
833
 
              svn_sort__array_insert(&new_modified_range, rangelist, *index);
 
861
              (*range_index)+=2;
 
862
              svn_sort__array_insert(&new_modified_range, rangelist,
 
863
                                     *range_index);
834
864
              /* Recurse with the new range. */
835
 
              adjust_remaining_ranges(rangelist, index, result_pool);
 
865
              adjust_remaining_ranges(rangelist, range_index, result_pool);
836
866
              break;
837
867
            }
838
868
        }
851
881
              /* The intersection between MODIFIED_RANGE and NEXT_RANGE is
852
882
                 absorbed by the latter. */
853
883
              modified_range->end = next_range->start;
854
 
              (*index)++;
 
884
              (*range_index)++;
855
885
            }
856
886
          break;
857
887
        }
871
901
              /* MODIFIED_RANGE absorbs the portion of NEXT_RANGE it overlaps
872
902
                 and NEXT_RANGE is truncated. */
873
903
              next_range->start = modified_range->end;
874
 
              (*index)++;
 
904
              (*range_index)++;
875
905
            }
876
906
          else
877
907
            {
878
908
              /* NEXT_RANGE absorbs the portion of MODIFIED_RANGE it overlaps
879
909
                 and MODIFIED_RANGE is truncated. */
880
910
              modified_range->end = next_range->start;
881
 
              (*index)++;
 
911
              (*range_index)++;
882
912
            }
883
913
          break;
884
914
        }
889
919
}
890
920
 
891
921
svn_error_t *
892
 
svn_rangelist_merge(apr_array_header_t **rangelist,
893
 
                    const apr_array_header_t *changes,
894
 
                    apr_pool_t *pool)
 
922
svn_rangelist_merge2(svn_rangelist_t *rangelist,
 
923
                     const svn_rangelist_t *changes,
 
924
                     apr_pool_t *result_pool,
 
925
                     apr_pool_t *scratch_pool)
895
926
{
896
927
  int i = 0;
897
928
  int j = 0;
898
 
  apr_pool_t *subpool = svn_pool_create(pool);
899
 
 
900
 
  /* We may modify CHANGES, so make a copy in SUBPOOL. */
901
 
  changes = svn_rangelist_dup(changes, subpool);
902
 
 
903
 
  while (i < (*rangelist)->nelts && j < changes->nelts)
 
929
 
 
930
  /* We may modify CHANGES, so make a copy in SCRATCH_POOL. */
 
931
  changes = svn_rangelist_dup(changes, scratch_pool);
 
932
 
 
933
  while (i < rangelist->nelts && j < changes->nelts)
904
934
    {
905
935
      svn_merge_range_t *range =
906
 
        APR_ARRAY_IDX(*rangelist, i, svn_merge_range_t *);
 
936
        APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *);
907
937
      svn_merge_range_t *change =
908
938
        APR_ARRAY_IDX(changes, j, svn_merge_range_t *);
909
939
      int res = svn_sort_compare_ranges(&range, &change);
934
964
                  /* RANGE and CHANGE have the same inheritability so
935
965
                     RANGE expands to absord CHANGE. */
936
966
                  range->end = change->end;
937
 
                  adjust_remaining_ranges(*rangelist, &i, pool);
 
967
                  adjust_remaining_ranges(rangelist, &i, result_pool);
938
968
                  j++;
939
969
                }
940
970
              else
967
997
                      /* CHANGE absorbs intersection with RANGE and RANGE
968
998
                         is truncated. */
969
999
                      svn_merge_range_t *range_copy =
970
 
                        svn_merge_range_dup(range, pool);
 
1000
                        svn_merge_range_dup(range, result_pool);
971
1001
                      range_copy->end = change->start;
972
1002
                      range->start = change->start;
973
 
                      svn_sort__array_insert(&range_copy, *rangelist, i++);
 
1003
                      svn_sort__array_insert(&range_copy, rangelist, i++);
974
1004
                    }
975
1005
                  else
976
1006
                    {
989
1019
            {
990
1020
              /* CHANGE is older than RANGE and the two do not
991
1021
                 adjoin or overlap, so insert a copy of CHANGE
992
 
                 into *RANGELIST. */
 
1022
                 into RANGELIST. */
993
1023
              svn_merge_range_t *change_copy =
994
 
                svn_merge_range_dup(change, pool);
995
 
              svn_sort__array_insert(&change_copy, *rangelist, i++);
 
1024
                svn_merge_range_dup(change, result_pool);
 
1025
              svn_sort__array_insert(&change_copy, rangelist, i++);
996
1026
              j++;
997
1027
            }
998
1028
          else if (change->end == range->start)
1008
1038
              else
1009
1039
                {
1010
1040
                  /* RANGE and CHANGE have different inheritability so insert
1011
 
                     a copy of CHANGE into *RANGELIST. */
 
1041
                     a copy of CHANGE into RANGELIST. */
1012
1042
                  svn_merge_range_t *change_copy =
1013
 
                    svn_merge_range_dup(change, pool);
1014
 
                  svn_sort__array_insert(&change_copy, *rangelist, i);
 
1043
                    svn_merge_range_dup(change, result_pool);
 
1044
                  svn_sort__array_insert(&change_copy, rangelist, i);
1015
1045
                  j++;
1016
1046
                }
1017
1047
            }
1028
1058
                      /* ...but if RANGE is expanded ensure that we don't
1029
1059
                         violate any rangelist invariants. */
1030
1060
                      range->end = change->end;
1031
 
                      adjust_remaining_ranges(*rangelist, &i, pool);
 
1061
                      adjust_remaining_ranges(rangelist, &i, result_pool);
1032
1062
                    }
1033
1063
                  j++;
1034
1064
                }
1038
1068
                    {
1039
1069
                      /* RANGE is inheritable so absorbs any part of CHANGE
1040
1070
                         it overlaps.  CHANGE is truncated and the remainder
1041
 
                         inserted into *RANGELIST. */
 
1071
                         inserted into RANGELIST. */
1042
1072
                      svn_merge_range_t *change_copy =
1043
 
                        svn_merge_range_dup(change, pool);
 
1073
                        svn_merge_range_dup(change, result_pool);
1044
1074
                      change_copy->end = range->start;
1045
1075
                      change->start = range->start;
1046
 
                      svn_sort__array_insert(&change_copy, *rangelist, i++);
 
1076
                      svn_sort__array_insert(&change_copy, rangelist, i++);
1047
1077
                    }
1048
1078
                  else
1049
1079
                    {
1079
1109
                        {
1080
1110
                          /* CHANGE and RANGE overlap. Set RANGE equal to its
1081
1111
                             intersection with CHANGE and take the remainder
1082
 
                             of RANGE and insert it into *RANGELIST. */
 
1112
                             of RANGE and insert it into RANGELIST. */
1083
1113
                          svn_merge_range_t *range_copy =
1084
 
                            svn_merge_range_dup(range, pool);
 
1114
                            svn_merge_range_dup(range, result_pool);
1085
1115
                          range_copy->start = change->end;
1086
1116
                          range->start = change->start;
1087
1117
                          range->end = change->end;
1088
1118
                          range->inheritable = TRUE;
1089
 
                          svn_sort__array_insert(&range_copy, *rangelist, ++i);
 
1119
                          svn_sort__array_insert(&range_copy, rangelist, ++i);
1090
1120
                          j++;
1091
1121
                        }
1092
1122
                    }
1093
 
                  else 
 
1123
                  else
1094
1124
                    {
1095
1125
                      /* CHANGE and RANGE share the same start rev, but
1096
1126
                         CHANGE is considered older because its end rev
1097
1127
                         is older.
1098
 
                         
 
1128
 
1099
1129
                         Insert the intersection of RANGE and CHANGE into
1100
 
                         *RANGELIST and then set RANGE to the non-intersecting
 
1130
                         RANGELIST and then set RANGE to the non-intersecting
1101
1131
                         portion of RANGE. */
1102
1132
                      svn_merge_range_t *range_copy =
1103
 
                        svn_merge_range_dup(range, pool);
 
1133
                        svn_merge_range_dup(range, result_pool);
1104
1134
                      range_copy->end = change->end;
1105
1135
                      range_copy->inheritable = TRUE;
1106
1136
                      range->start = change->end;
1107
 
                      svn_sort__array_insert(&range_copy, *rangelist, i++);
 
1137
                      svn_sort__array_insert(&range_copy, rangelist, i++);
1108
1138
                      j++;
1109
1139
                    }
1110
1140
                }
1112
1142
        }
1113
1143
    }
1114
1144
 
1115
 
  /* Copy any remaining elements in CHANGES into *RANGELIST. */
 
1145
  /* Copy any remaining elements in CHANGES into RANGELIST. */
1116
1146
  for (; j < (changes)->nelts; j++)
1117
1147
    {
1118
1148
      svn_merge_range_t *change =
1119
1149
        APR_ARRAY_IDX(changes, j, svn_merge_range_t *);
1120
1150
      svn_merge_range_t *change_copy = svn_merge_range_dup(change,
1121
 
                                                           pool);
1122
 
      svn_sort__array_insert(&change_copy, *rangelist, (*rangelist)->nelts);
 
1151
                                                           result_pool);
 
1152
      svn_sort__array_insert(&change_copy, rangelist, rangelist->nelts);
1123
1153
    }
1124
1154
 
1125
 
  svn_pool_destroy(subpool);
1126
1155
  return SVN_NO_ERROR;
1127
1156
}
1128
1157
 
1166
1195
}
1167
1196
 
1168
1197
svn_error_t *
1169
 
svn_rangelist_reverse(apr_array_header_t *rangelist, apr_pool_t *pool)
 
1198
svn_rangelist_reverse(svn_rangelist_t *rangelist, apr_pool_t *pool)
1170
1199
{
1171
 
  int i, swap_index;
1172
 
  svn_merge_range_t range;
1173
 
  for (i = 0; i < rangelist->nelts / 2; i++)
 
1200
  int i;
 
1201
 
 
1202
  svn_sort__array_reverse(rangelist, pool);
 
1203
 
 
1204
  for (i = 0; i < rangelist->nelts; i++)
1174
1205
    {
1175
 
      swap_index = rangelist->nelts - i - 1;
1176
 
      range = *APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *);
1177
 
      *APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *) =
1178
 
        *APR_ARRAY_IDX(rangelist, swap_index, svn_merge_range_t *);
1179
 
      *APR_ARRAY_IDX(rangelist, swap_index, svn_merge_range_t *) = range;
1180
 
      range_swap_endpoints(APR_ARRAY_IDX(rangelist, swap_index,
1181
 
                                         svn_merge_range_t *));
1182
1206
      range_swap_endpoints(APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *));
1183
1207
    }
1184
1208
 
1185
 
  /* If there's an odd number of elements, we still need to swap the
1186
 
     end points of the remaining range. */
1187
 
  if (rangelist->nelts % 2 == 1)
1188
 
    range_swap_endpoints(APR_ARRAY_IDX(rangelist, rangelist->nelts / 2,
1189
 
                                       svn_merge_range_t *));
1190
 
 
1191
1209
  return SVN_NO_ERROR;
1192
1210
}
1193
1211
 
1194
1212
void
1195
 
svn_rangelist__set_inheritance(apr_array_header_t *rangelist,
 
1213
svn_rangelist__set_inheritance(svn_rangelist_t *rangelist,
1196
1214
                               svn_boolean_t inheritable)
1197
1215
{
1198
1216
  if (rangelist)
1222
1240
           hi;
1223
1241
           hi = apr_hash_next(hi))
1224
1242
        {
1225
 
          apr_array_header_t *rangelist = svn__apr_hash_index_val(hi);
 
1243
          svn_rangelist_t *rangelist = svn__apr_hash_index_val(hi);
1226
1244
 
1227
1245
          if (rangelist)
1228
1246
            svn_rangelist__set_inheritance(rangelist, inheritable);
1242
1260
 
1243
1261
   If CONSIDER_INHERITANCE is true, then take the inheritance of the
1244
1262
   ranges in RANGELIST1 and RANGELIST2 into account when comparing them
1245
 
   for intersection, see the doc string for svn_rangelist_intersection().
 
1263
   for intersection, see the doc string for svn_rangelist_intersect().
1246
1264
 
1247
1265
   If CONSIDER_INHERITANCE is false, then ranges with differing inheritance
1248
1266
   may intersect, but the resulting intersection is non-inheritable only
1264
1282
 
1265
1283
   Allocate the contents of *OUTPUT in POOL. */
1266
1284
static svn_error_t *
1267
 
rangelist_intersect_or_remove(apr_array_header_t **output,
1268
 
                              const apr_array_header_t *rangelist1,
1269
 
                              const apr_array_header_t *rangelist2,
 
1285
rangelist_intersect_or_remove(svn_rangelist_t **output,
 
1286
                              const svn_rangelist_t *rangelist1,
 
1287
                              const svn_rangelist_t *rangelist2,
1270
1288
                              svn_boolean_t do_remove,
1271
1289
                              svn_boolean_t consider_inheritance,
1272
1290
                              apr_pool_t *pool)
1318
1336
              tmp_range.inheritable =
1319
1337
                (elt2->inheritable || elt1->inheritable);
1320
1338
              SVN_ERR(combine_with_lastrange(&tmp_range, *output,
1321
 
                                             consider_inheritance, pool,
 
1339
                                             consider_inheritance,
1322
1340
                                             pool));
1323
1341
            }
1324
1342
 
1355
1373
 
1356
1374
              SVN_ERR(combine_with_lastrange(&tmp_range,
1357
1375
                                             *output, consider_inheritance,
1358
 
                                             pool, pool));
 
1376
                                             pool));
1359
1377
            }
1360
1378
 
1361
1379
          /* Set up the rest of the rangelist2 range for further
1376
1394
                  SVN_ERR(combine_with_lastrange(&tmp_range,
1377
1395
                                                 *output,
1378
1396
                                                 consider_inheritance,
1379
 
                                                 pool, pool));
 
1397
                                                 pool));
1380
1398
                }
1381
1399
 
1382
1400
              working_elt2.start = elt1->end;
1428
1446
      if (i2 == lasti2 && i2 < rangelist2->nelts)
1429
1447
        {
1430
1448
          SVN_ERR(combine_with_lastrange(&working_elt2, *output,
1431
 
                                         consider_inheritance, pool, pool));
 
1449
                                         consider_inheritance, pool));
1432
1450
          i2++;
1433
1451
        }
1434
1452
 
1439
1457
                                                 svn_merge_range_t *);
1440
1458
 
1441
1459
          SVN_ERR(combine_with_lastrange(elt, *output,
1442
 
                                         consider_inheritance, pool, pool));
 
1460
                                         consider_inheritance, pool));
1443
1461
        }
1444
1462
    }
1445
1463
 
1448
1466
 
1449
1467
 
1450
1468
svn_error_t *
1451
 
svn_rangelist_intersect(apr_array_header_t **output,
1452
 
                        const apr_array_header_t *rangelist1,
1453
 
                        const apr_array_header_t *rangelist2,
 
1469
svn_rangelist_intersect(svn_rangelist_t **output,
 
1470
                        const svn_rangelist_t *rangelist1,
 
1471
                        const svn_rangelist_t *rangelist2,
1454
1472
                        svn_boolean_t consider_inheritance,
1455
1473
                        apr_pool_t *pool)
1456
1474
{
1459
1477
}
1460
1478
 
1461
1479
svn_error_t *
1462
 
svn_rangelist_remove(apr_array_header_t **output,
1463
 
                     const apr_array_header_t *eraser,
1464
 
                     const apr_array_header_t *whiteboard,
 
1480
svn_rangelist_remove(svn_rangelist_t **output,
 
1481
                     const svn_rangelist_t *eraser,
 
1482
                     const svn_rangelist_t *whiteboard,
1465
1483
                     svn_boolean_t consider_inheritance,
1466
1484
                     apr_pool_t *pool)
1467
1485
{
1470
1488
}
1471
1489
 
1472
1490
svn_error_t *
1473
 
svn_rangelist_diff(apr_array_header_t **deleted, apr_array_header_t **added,
1474
 
                   const apr_array_header_t *from, const apr_array_header_t *to,
 
1491
svn_rangelist_diff(svn_rangelist_t **deleted, svn_rangelist_t **added,
 
1492
                   const svn_rangelist_t *from, const svn_rangelist_t *to,
1475
1493
                   svn_boolean_t consider_inheritance,
1476
1494
                   apr_pool_t *pool)
1477
1495
{
1532
1550
  /* hash_a is FROM mergeinfo,
1533
1551
     hash_b is TO mergeinfo. */
1534
1552
  struct mergeinfo_diff_baton *cb = baton;
1535
 
  apr_array_header_t *from_rangelist, *to_rangelist;
 
1553
  svn_rangelist_t *from_rangelist, *to_rangelist;
1536
1554
  const char *path = key;
1537
1555
  if (status == svn_hash_diff_key_both)
1538
1556
    {
1539
1557
      /* Record any deltas (additions or deletions). */
1540
 
      apr_array_header_t *deleted_rangelist, *added_rangelist;
1541
 
      from_rangelist = apr_hash_get(cb->from, path, APR_HASH_KEY_STRING);
1542
 
      to_rangelist = apr_hash_get(cb->to, path, APR_HASH_KEY_STRING);
 
1558
      svn_rangelist_t *deleted_rangelist, *added_rangelist;
 
1559
      from_rangelist = apr_hash_get(cb->from, path, klen);
 
1560
      to_rangelist = apr_hash_get(cb->to, path, klen);
1543
1561
      SVN_ERR(svn_rangelist_diff(&deleted_rangelist, &added_rangelist,
1544
1562
                                 from_rangelist, to_rangelist,
1545
1563
                                 cb->consider_inheritance, cb->pool));
1546
1564
      if (cb->deleted && deleted_rangelist->nelts > 0)
1547
 
        apr_hash_set(cb->deleted, apr_pstrdup(cb->pool, path),
1548
 
                     APR_HASH_KEY_STRING, deleted_rangelist);
 
1565
        apr_hash_set(cb->deleted, apr_pstrmemdup(cb->pool, path, klen),
 
1566
                     klen, deleted_rangelist);
1549
1567
      if (cb->added && added_rangelist->nelts > 0)
1550
 
        apr_hash_set(cb->added, apr_pstrdup(cb->pool, path),
1551
 
                     APR_HASH_KEY_STRING, added_rangelist);
 
1568
        apr_hash_set(cb->added, apr_pstrmemdup(cb->pool, path, klen),
 
1569
                     klen, added_rangelist);
1552
1570
    }
1553
1571
  else if ((status == svn_hash_diff_key_a) && cb->deleted)
1554
1572
    {
1555
 
      from_rangelist = apr_hash_get(cb->from, path, APR_HASH_KEY_STRING);
1556
 
      apr_hash_set(cb->deleted, apr_pstrdup(cb->pool, path),
1557
 
                   APR_HASH_KEY_STRING,
 
1573
      from_rangelist = apr_hash_get(cb->from, path, klen);
 
1574
      apr_hash_set(cb->deleted, apr_pstrmemdup(cb->pool, path, klen), klen,
1558
1575
                   svn_rangelist_dup(from_rangelist, cb->pool));
1559
1576
    }
1560
1577
  else if ((status == svn_hash_diff_key_b) && cb->added)
1561
1578
    {
1562
 
      to_rangelist = apr_hash_get(cb->to, path, APR_HASH_KEY_STRING);
1563
 
      apr_hash_set(cb->added, apr_pstrdup(cb->pool, path), APR_HASH_KEY_STRING,
 
1579
      to_rangelist = apr_hash_get(cb->to, path, klen);
 
1580
      apr_hash_set(cb->added, apr_pstrmemdup(cb->pool, path, klen), klen,
1564
1581
                   svn_rangelist_dup(to_rangelist, cb->pool));
1565
1582
    }
1566
1583
  return SVN_NO_ERROR;
1588
1605
}
1589
1606
 
1590
1607
svn_error_t *
1591
 
svn_mergeinfo_diff(svn_mergeinfo_t *deleted, svn_mergeinfo_t *added,
1592
 
                   svn_mergeinfo_t from, svn_mergeinfo_t to,
1593
 
                   svn_boolean_t consider_inheritance,
1594
 
                   apr_pool_t *pool)
 
1608
svn_mergeinfo_diff2(svn_mergeinfo_t *deleted, svn_mergeinfo_t *added,
 
1609
                    svn_mergeinfo_t from, svn_mergeinfo_t to,
 
1610
                    svn_boolean_t consider_inheritance,
 
1611
                    apr_pool_t *result_pool,
 
1612
                    apr_pool_t *scratch_pool)
1595
1613
{
1596
1614
  if (from && to == NULL)
1597
1615
    {
1598
 
      *deleted = svn_mergeinfo_dup(from, pool);
1599
 
      *added = apr_hash_make(pool);
 
1616
      *deleted = svn_mergeinfo_dup(from, result_pool);
 
1617
      *added = svn_hash__make(result_pool);
1600
1618
    }
1601
1619
  else if (from == NULL && to)
1602
1620
    {
1603
 
      *deleted = apr_hash_make(pool);
1604
 
      *added = svn_mergeinfo_dup(to, pool);
 
1621
      *deleted = svn_hash__make(result_pool);
 
1622
      *added = svn_mergeinfo_dup(to, result_pool);
1605
1623
    }
1606
1624
  else
1607
1625
    {
1608
 
      *deleted = apr_hash_make(pool);
1609
 
      *added = apr_hash_make(pool);
 
1626
      *deleted = svn_hash__make(result_pool);
 
1627
      *added = svn_hash__make(result_pool);
1610
1628
 
1611
1629
      if (from && to)
1612
1630
        {
1613
1631
          SVN_ERR(walk_mergeinfo_hash_for_diff(from, to, *deleted, *added,
1614
 
                                               consider_inheritance, pool,
1615
 
                                               pool));
 
1632
                                               consider_inheritance,
 
1633
                                               result_pool, scratch_pool));
1616
1634
        }
1617
1635
    }
1618
1636
 
1626
1644
                      svn_boolean_t consider_inheritance,
1627
1645
                      apr_pool_t *pool)
1628
1646
{
1629
 
  if (apr_hash_count(info1) == apr_hash_count(info2))
1630
 
    {
1631
 
      svn_mergeinfo_t deleted, added;
1632
 
      SVN_ERR(svn_mergeinfo_diff(&deleted, &added, info1, info2,
1633
 
                                 consider_inheritance, pool));
1634
 
      *is_equal = apr_hash_count(deleted) == 0 && apr_hash_count(added) == 0;
1635
 
    }
1636
 
  else
1637
 
    {
1638
 
      *is_equal = FALSE;
1639
 
    }
 
1647
  apr_hash_index_t *hi;
 
1648
 
 
1649
  *is_equal = FALSE;
 
1650
 
 
1651
  /* special cases: at least one side has no merge info */
 
1652
  if (info1 == NULL && info2 == NULL)
 
1653
    {
 
1654
      *is_equal = TRUE;
 
1655
      return SVN_NO_ERROR;
 
1656
    }
 
1657
 
 
1658
  if (info1 == NULL ||  info2 == NULL)
 
1659
    return SVN_NO_ERROR;
 
1660
 
 
1661
  /* trivial case: different number of paths -> unequal */
 
1662
  if (apr_hash_count(info1) != apr_hash_count(info2))
 
1663
    return SVN_NO_ERROR;
 
1664
 
 
1665
  /* compare range lists for all paths */
 
1666
  for (hi = apr_hash_first(pool, info1); hi; hi = apr_hash_next(hi))
 
1667
    {
 
1668
      const char *key;
 
1669
      apr_ssize_t key_length;
 
1670
      svn_rangelist_t *lhs, *rhs;
 
1671
      int i;
 
1672
      svn_rangelist_t *deleted, *added;
 
1673
 
 
1674
      /* get both path lists */
 
1675
      apr_hash_this(hi, (const void**)&key, &key_length, (void **)&lhs);
 
1676
      rhs = apr_hash_get(info2, key, key_length);
 
1677
 
 
1678
      /* missing on one side? */
 
1679
      if (rhs == NULL)
 
1680
        return SVN_NO_ERROR;
 
1681
 
 
1682
      /* quick compare: the range lists will often be a perfect match */
 
1683
      if (lhs->nelts == rhs->nelts)
 
1684
        {
 
1685
          for (i = 0; i < lhs->nelts; ++i)
 
1686
            {
 
1687
              svn_merge_range_t *lrange
 
1688
                = APR_ARRAY_IDX(lhs, i, svn_merge_range_t *);
 
1689
              svn_merge_range_t *rrange
 
1690
                = APR_ARRAY_IDX(rhs, i, svn_merge_range_t *);
 
1691
 
 
1692
              /* range mismatch? -> needs detailed comparison */
 
1693
              if (   lrange->start != rrange->start
 
1694
                  || lrange->end != rrange->end)
 
1695
                break;
 
1696
 
 
1697
              /* inheritance mismatch? -> merge info differs */
 
1698
              if (   consider_inheritance
 
1699
                  && lrange->inheritable != rrange->inheritable)
 
1700
                return SVN_NO_ERROR;
 
1701
            }
 
1702
 
 
1703
          /* all ranges found to match -> next path */
 
1704
          if (i == lhs->nelts)
 
1705
            continue;
 
1706
        }
 
1707
 
 
1708
      /* range lists differ but there are many ways to sort and aggregate
 
1709
         revisions into ranges. Do a full diff on them. */
 
1710
      SVN_ERR(svn_rangelist_diff(&deleted, &added, lhs, rhs,
 
1711
                                  consider_inheritance, pool));
 
1712
      if (deleted->nelts || added->nelts)
 
1713
        return SVN_NO_ERROR;
 
1714
    }
 
1715
 
 
1716
  /* no mismatch found */
 
1717
  *is_equal = TRUE;
1640
1718
  return SVN_NO_ERROR;
1641
1719
}
1642
1720
 
1643
1721
svn_error_t *
1644
 
svn_mergeinfo_merge(svn_mergeinfo_t mergeinfo, svn_mergeinfo_t changes,
1645
 
                    apr_pool_t *pool)
 
1722
svn_mergeinfo_merge2(svn_mergeinfo_t mergeinfo,
 
1723
                     svn_mergeinfo_t changes,
 
1724
                     apr_pool_t *result_pool,
 
1725
                     apr_pool_t *scratch_pool)
1646
1726
{
1647
 
  apr_array_header_t *sorted1, *sorted2;
1648
 
  int i, j;
 
1727
  apr_hash_index_t *hi;
 
1728
  apr_pool_t *iterpool;
1649
1729
 
1650
1730
  if (!apr_hash_count(changes))
1651
1731
    return SVN_NO_ERROR;
1652
1732
 
1653
 
  sorted1 = svn_sort__hash(mergeinfo, svn_sort_compare_items_as_paths, pool);
1654
 
  sorted2 = svn_sort__hash(changes, svn_sort_compare_items_as_paths, pool);
1655
 
 
1656
 
  i = 0;
1657
 
  j = 0;
1658
 
  while (i < sorted1->nelts && j < sorted2->nelts)
 
1733
  iterpool = svn_pool_create(scratch_pool);
 
1734
  for (hi = apr_hash_first(scratch_pool, changes); hi; hi = apr_hash_next(hi))
1659
1735
    {
1660
 
      svn_sort__item_t elt1, elt2;
1661
 
      int res;
1662
 
 
1663
 
      elt1 = APR_ARRAY_IDX(sorted1, i, svn_sort__item_t);
1664
 
      elt2 = APR_ARRAY_IDX(sorted2, j, svn_sort__item_t);
1665
 
      res = svn_sort_compare_items_as_paths(&elt1, &elt2);
1666
 
 
1667
 
      if (res == 0)
1668
 
        {
1669
 
          apr_array_header_t *rl1, *rl2;
1670
 
 
1671
 
          rl1 = elt1.value;
1672
 
          rl2 = elt2.value;
1673
 
 
1674
 
          SVN_ERR(svn_rangelist_merge(&rl1, rl2,
1675
 
                                      pool));
1676
 
          apr_hash_set(mergeinfo, elt1.key, elt1.klen, rl1);
1677
 
          i++;
1678
 
          j++;
1679
 
        }
1680
 
      else if (res < 0)
1681
 
        {
1682
 
          i++;
 
1736
      const char *key;
 
1737
      apr_ssize_t klen;
 
1738
      svn_rangelist_t *to_insert;
 
1739
      svn_rangelist_t *target;
 
1740
 
 
1741
      /* get ranges to insert and the target ranges list of that insertion */
 
1742
      apr_hash_this(hi, (const void**)&key, &klen, (void*)&to_insert);
 
1743
      target = apr_hash_get(mergeinfo, key, klen);
 
1744
 
 
1745
      /* if range list exists, just expand on it.
 
1746
       * Otherwise, add new hash entry. */
 
1747
      if (target)
 
1748
        {
 
1749
          SVN_ERR(svn_rangelist_merge2(target, to_insert, result_pool,
 
1750
                                       iterpool));
 
1751
          svn_pool_clear(iterpool);
1683
1752
        }
1684
1753
      else
1685
 
        {
1686
 
          apr_hash_set(mergeinfo, elt2.key, elt2.klen, elt2.value);
1687
 
          j++;
1688
 
        }
 
1754
        apr_hash_set(mergeinfo, key, klen, to_insert);
1689
1755
    }
1690
1756
 
1691
 
  /* Copy back any remaining elements from the second hash. */
1692
 
  for (; j < sorted2->nelts; j++)
1693
 
    {
1694
 
      svn_sort__item_t elt = APR_ARRAY_IDX(sorted2, j, svn_sort__item_t);
1695
 
      apr_hash_set(mergeinfo, elt.key, elt.klen, elt.value);
1696
 
    }
 
1757
  svn_pool_destroy(iterpool);
1697
1758
 
1698
1759
  return SVN_NO_ERROR;
1699
1760
}
1727
1788
          svn_mergeinfo_t mergeinfo = cat_elt.value;
1728
1789
          svn_mergeinfo_t changes_mergeinfo = change_elt.value;
1729
1790
 
1730
 
          SVN_ERR(svn_mergeinfo_merge(mergeinfo, changes_mergeinfo,
1731
 
                                      result_pool));
 
1791
          SVN_ERR(svn_mergeinfo_merge2(mergeinfo, changes_mergeinfo,
 
1792
                                       result_pool, scratch_pool));
1732
1793
          apr_hash_set(mergeinfo_cat, cat_elt.key, cat_elt.klen, mergeinfo);
1733
1794
          i++;
1734
1795
          j++;
1762
1823
}
1763
1824
 
1764
1825
svn_error_t *
1765
 
svn_mergeinfo_intersect(svn_mergeinfo_t *mergeinfo,
1766
 
                        svn_mergeinfo_t mergeinfo1,
1767
 
                        svn_mergeinfo_t mergeinfo2,
1768
 
                        apr_pool_t *pool)
1769
 
{
1770
 
  return svn_mergeinfo_intersect2(mergeinfo, mergeinfo1, mergeinfo2,
1771
 
                                  TRUE, pool, pool);
1772
 
}
1773
 
 
1774
 
svn_error_t *
1775
1826
svn_mergeinfo_intersect2(svn_mergeinfo_t *mergeinfo,
1776
1827
                         svn_mergeinfo_t mergeinfo1,
1777
1828
                         svn_mergeinfo_t mergeinfo2,
1794
1845
       hi; hi = apr_hash_next(hi))
1795
1846
    {
1796
1847
      const char *path = svn__apr_hash_index_key(hi);
1797
 
      apr_array_header_t *rangelist1 = svn__apr_hash_index_val(hi);
1798
 
      apr_array_header_t *rangelist2;
 
1848
      svn_rangelist_t *rangelist1 = svn__apr_hash_index_val(hi);
 
1849
      svn_rangelist_t *rangelist2;
1799
1850
 
1800
1851
      svn_pool_clear(iterpool);
1801
 
      rangelist2 = apr_hash_get(mergeinfo2, path, APR_HASH_KEY_STRING);
 
1852
      rangelist2 = svn_hash_gets(mergeinfo2, path);
1802
1853
      if (rangelist2)
1803
1854
        {
1804
1855
          SVN_ERR(svn_rangelist_intersect(&rangelist2, rangelist1, rangelist2,
1805
1856
                                          consider_inheritance, iterpool));
1806
1857
          if (rangelist2->nelts > 0)
1807
 
            apr_hash_set(*mergeinfo,
1808
 
                         apr_pstrdup(result_pool, path),
1809
 
                         APR_HASH_KEY_STRING,
1810
 
                         svn_rangelist_dup(rangelist2, result_pool));
 
1858
            svn_hash_sets(*mergeinfo, apr_pstrdup(result_pool, path),
 
1859
                          svn_rangelist_dup(rangelist2, result_pool));
1811
1860
        }
1812
1861
    }
1813
1862
  svn_pool_destroy(iterpool);
1815
1864
}
1816
1865
 
1817
1866
svn_error_t *
1818
 
svn_mergeinfo_remove(svn_mergeinfo_t *mergeinfo, svn_mergeinfo_t eraser,
1819
 
                     svn_mergeinfo_t whiteboard, apr_pool_t *pool)
1820
 
{
1821
 
  return svn_mergeinfo_remove2(mergeinfo, eraser, whiteboard, TRUE, pool,
1822
 
                               pool);
1823
 
}
1824
 
 
1825
 
svn_error_t *
1826
1867
svn_mergeinfo_remove2(svn_mergeinfo_t *mergeinfo,
1827
1868
                      svn_mergeinfo_t eraser,
1828
1869
                      svn_mergeinfo_t whiteboard,
1838
1879
 
1839
1880
svn_error_t *
1840
1881
svn_rangelist_to_string(svn_string_t **output,
1841
 
                        const apr_array_header_t *rangelist,
 
1882
                        const svn_rangelist_t *rangelist,
1842
1883
                        apr_pool_t *pool)
1843
1884
{
1844
 
  svn_stringbuf_t *buf = svn_stringbuf_create("", pool);
 
1885
  svn_stringbuf_t *buf = svn_stringbuf_create_empty(pool);
1845
1886
 
1846
1887
  if (rangelist->nelts > 0)
1847
1888
    {
1878
1919
                       const char *prefix,
1879
1920
                       apr_pool_t *pool)
1880
1921
{
1881
 
  *output = svn_stringbuf_create("", pool);
 
1922
  *output = svn_stringbuf_create_empty(pool);
1882
1923
 
1883
1924
  if (apr_hash_count(input) > 0)
1884
1925
    {
1911
1952
svn_mergeinfo_to_string(svn_string_t **output, svn_mergeinfo_t input,
1912
1953
                        apr_pool_t *pool)
1913
1954
{
1914
 
  if (apr_hash_count(input) > 0)
1915
 
    {
1916
 
      svn_stringbuf_t *mergeinfo_buf;
1917
 
      SVN_ERR(mergeinfo_to_stringbuf(&mergeinfo_buf, input, NULL, pool));
1918
 
      *output = svn_stringbuf__morph_into_string(mergeinfo_buf);
1919
 
    }
1920
 
  else
1921
 
    {
1922
 
      *output = svn_string_create("", pool);
1923
 
    }
 
1955
  svn_stringbuf_t *mergeinfo_buf;
 
1956
 
 
1957
  SVN_ERR(mergeinfo_to_stringbuf(&mergeinfo_buf, input, NULL, pool));
 
1958
  *output = svn_stringbuf__morph_into_string(mergeinfo_buf);
1924
1959
  return SVN_NO_ERROR;
1925
1960
}
1926
1961
 
1952
1987
      const char *key = svn__apr_hash_index_key(hi);
1953
1988
      svn_mergeinfo_t val = svn__apr_hash_index_val(hi);
1954
1989
 
1955
 
      apr_hash_set(new_mergeinfo_catalog,
1956
 
                   apr_pstrdup(pool, key),
1957
 
                   APR_HASH_KEY_STRING,
1958
 
                   svn_mergeinfo_dup(val, pool));
 
1990
      svn_hash_sets(new_mergeinfo_catalog, apr_pstrdup(pool, key),
 
1991
                    svn_mergeinfo_dup(val, pool));
1959
1992
    }
1960
1993
 
1961
1994
  return new_mergeinfo_catalog;
1964
1997
svn_mergeinfo_t
1965
1998
svn_mergeinfo_dup(svn_mergeinfo_t mergeinfo, apr_pool_t *pool)
1966
1999
{
1967
 
  svn_mergeinfo_t new_mergeinfo = apr_hash_make(pool);
 
2000
  svn_mergeinfo_t new_mergeinfo = svn_hash__make(pool);
1968
2001
  apr_hash_index_t *hi;
1969
2002
 
1970
2003
  for (hi = apr_hash_first(pool, mergeinfo); hi; hi = apr_hash_next(hi))
1971
2004
    {
1972
2005
      const char *path = svn__apr_hash_index_key(hi);
1973
2006
      apr_ssize_t pathlen = svn__apr_hash_index_klen(hi);
1974
 
      apr_array_header_t *rangelist = svn__apr_hash_index_val(hi);
 
2007
      svn_rangelist_t *rangelist = svn__apr_hash_index_val(hi);
1975
2008
 
1976
2009
      apr_hash_set(new_mergeinfo, apr_pstrmemdup(pool, path, pathlen), pathlen,
1977
2010
                   svn_rangelist_dup(rangelist, pool));
1999
2032
    {
2000
2033
      const char *key = svn__apr_hash_index_key(hi);
2001
2034
      apr_ssize_t keylen = svn__apr_hash_index_klen(hi);
2002
 
      apr_array_header_t *rangelist = svn__apr_hash_index_val(hi);
2003
 
      apr_array_header_t *inheritable_rangelist;
 
2035
      svn_rangelist_t *rangelist = svn__apr_hash_index_val(hi);
 
2036
      svn_rangelist_t *inheritable_rangelist;
2004
2037
 
2005
2038
      if (!path || svn_path_compare_paths(path, key) == 0)
2006
2039
        SVN_ERR(svn_rangelist_inheritable2(&inheritable_rangelist, rangelist,
2022
2055
 
2023
2056
 
2024
2057
svn_error_t *
2025
 
svn_rangelist_inheritable2(apr_array_header_t **inheritable_rangelist,
2026
 
                           const apr_array_header_t *rangelist,
 
2058
svn_rangelist_inheritable2(svn_rangelist_t **inheritable_rangelist,
 
2059
                           const svn_rangelist_t *rangelist,
2027
2060
                           svn_revnum_t start,
2028
2061
                           svn_revnum_t end,
2029
2062
                           svn_boolean_t inheritable,
2060
2093
        {
2061
2094
          /* We want only the non-inheritable ranges bound by START
2062
2095
             and END removed. */
2063
 
          apr_array_header_t *ranges_inheritable =
 
2096
          svn_rangelist_t *ranges_inheritable =
2064
2097
            svn_rangelist__initialize(start, end, inheritable, scratch_pool);
2065
2098
 
2066
2099
          if (rangelist->nelts)
2086
2119
      for (hi = apr_hash_first(pool, mergeinfo); hi; hi = apr_hash_next(hi))
2087
2120
        {
2088
2121
          const char *path = svn__apr_hash_index_key(hi);
2089
 
          apr_array_header_t *rangelist = svn__apr_hash_index_val(hi);
 
2122
          svn_rangelist_t *rangelist = svn__apr_hash_index_val(hi);
2090
2123
 
2091
2124
          if (rangelist->nelts == 0)
2092
2125
            {
2093
 
              apr_hash_set(mergeinfo, path, APR_HASH_KEY_STRING, NULL);
 
2126
              svn_hash_sets(mergeinfo, path, NULL);
2094
2127
              removed_some_ranges = TRUE;
2095
2128
            }
2096
2129
        }
2105
2138
                                          apr_pool_t *pool)
2106
2139
{
2107
2140
  apr_hash_index_t *hi;
2108
 
  apr_ssize_t prefix_len = strlen(prefix_path);
2109
2141
 
2110
2142
  SVN_ERR_ASSERT(prefix_path[0] == '/');
2111
2143
 
2114
2146
  for (hi = apr_hash_first(pool, in_catalog); hi; hi = apr_hash_next(hi))
2115
2147
    {
2116
2148
      const char *original_path = svn__apr_hash_index_key(hi);
2117
 
      apr_ssize_t klen = svn__apr_hash_index_klen(hi);
2118
2149
      svn_mergeinfo_t value = svn__apr_hash_index_val(hi);
2119
 
      apr_ssize_t padding = 0;
2120
 
 
2121
 
      SVN_ERR_ASSERT(klen >= prefix_len);
2122
 
      SVN_ERR_ASSERT(svn_fspath__is_ancestor(prefix_path, original_path));
2123
 
 
2124
 
      /* If the ORIGINAL_PATH doesn't match the PREFIX_PATH exactly
2125
 
         and we're not simply removing a single leading slash (such as
2126
 
         when PREFIX_PATH is "/"), we advance our string offset by an
2127
 
         extra character (to get past the directory separator that
2128
 
         follows the prefix).  */
2129
 
      if ((strcmp(original_path, prefix_path) != 0) && (prefix_len != 1))
2130
 
        padding = 1;
2131
 
 
2132
 
      apr_hash_set(*out_catalog, original_path + prefix_len + padding,
2133
 
                   klen - prefix_len - padding, value);
 
2150
      const char *new_path;
 
2151
 
 
2152
      new_path = svn_fspath__skip_ancestor(prefix_path, original_path);
 
2153
      SVN_ERR_ASSERT(new_path);
 
2154
 
 
2155
      svn_hash_sets(*out_catalog, new_path, value);
2134
2156
    }
2135
2157
 
2136
2158
  return SVN_NO_ERROR;
2157
2179
      if (original_path[0] == '/')
2158
2180
        original_path++;
2159
2181
 
2160
 
      apr_hash_set(*out_catalog,
2161
 
                   svn_dirent_join(prefix_path, original_path, result_pool),
2162
 
                   APR_HASH_KEY_STRING, value);
 
2182
      svn_hash_sets(*out_catalog,
 
2183
                    svn_dirent_join(prefix_path, original_path, result_pool),
 
2184
                    value);
2163
2185
    }
2164
2186
 
2165
2187
  return SVN_NO_ERROR;
2182
2204
       hi;
2183
2205
       hi = apr_hash_next(hi))
2184
2206
    {
2185
 
      const char *path = svn__apr_hash_index_key(hi);
2186
 
      apr_array_header_t *rangelist = svn__apr_hash_index_val(hi);
 
2207
      const char *fspath = svn__apr_hash_index_key(hi);
 
2208
      svn_rangelist_t *rangelist = svn__apr_hash_index_val(hi);
2187
2209
 
2188
 
      apr_hash_set(*out_mergeinfo,
2189
 
                   svn_dirent_join(path, suffix_relpath, result_pool),
2190
 
                   APR_HASH_KEY_STRING,
2191
 
                   svn_rangelist_dup(rangelist, result_pool));
 
2210
      svn_hash_sets(*out_mergeinfo,
 
2211
                    svn_fspath__join(fspath, suffix_relpath, result_pool),
 
2212
                    rangelist);
2192
2213
    }
2193
2214
 
2194
2215
  return SVN_NO_ERROR;
2195
2216
}
2196
2217
 
2197
 
apr_array_header_t *
2198
 
svn_rangelist_dup(const apr_array_header_t *rangelist, apr_pool_t *pool)
 
2218
svn_rangelist_t *
 
2219
svn_rangelist_dup(const svn_rangelist_t *rangelist, apr_pool_t *pool)
2199
2220
{
2200
 
  apr_array_header_t *new_rl = apr_array_make(pool, rangelist->nelts,
2201
 
                                              sizeof(svn_merge_range_t *));
 
2221
  svn_rangelist_t *new_rl = apr_array_make(pool, rangelist->nelts,
 
2222
                                           sizeof(svn_merge_range_t *));
 
2223
 
 
2224
  /* allocate target range buffer with a single operation */
 
2225
  svn_merge_range_t *copy = apr_palloc(pool, sizeof(*copy) * rangelist->nelts);
2202
2226
  int i;
2203
2227
 
 
2228
  /* fill it iteratively and link it into the range list */
2204
2229
  for (i = 0; i < rangelist->nelts; i++)
2205
2230
    {
2206
 
      APR_ARRAY_PUSH(new_rl, svn_merge_range_t *) =
2207
 
        svn_merge_range_dup(APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *),
2208
 
                            pool);
 
2231
      memcpy(copy + i,
 
2232
             APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *),
 
2233
             sizeof(*copy));
 
2234
      APR_ARRAY_PUSH(new_rl, svn_merge_range_t *) = copy + i;
2209
2235
    }
2210
2236
 
2211
2237
  return new_rl;
2247
2273
      apr_array_header_t *sorted_catalog =
2248
2274
        svn_sort__hash(catalog, svn_sort_compare_items_as_paths, pool);
2249
2275
 
2250
 
      output_buf = svn_stringbuf_create("", pool);
 
2276
      output_buf = svn_stringbuf_create_empty(pool);
2251
2277
      for (i = 0; i < sorted_catalog->nelts; i++)
2252
2278
        {
2253
2279
          svn_sort__item_t elt =
2293
2319
}
2294
2320
 
2295
2321
svn_error_t *
2296
 
svn_mergeinfo__to_formatted_string(svn_string_t **output,
2297
 
                                   svn_mergeinfo_t mergeinfo,
2298
 
                                   const char *prefix,
2299
 
                                   apr_pool_t *pool)
2300
 
{
2301
 
  svn_stringbuf_t *output_buf = NULL;
2302
 
 
2303
 
  if (mergeinfo && apr_hash_count(mergeinfo))
2304
 
    {
2305
 
      SVN_ERR(mergeinfo_to_stringbuf(&output_buf, mergeinfo,
2306
 
                                     prefix ? prefix : "", pool));
2307
 
      svn_stringbuf_appendcstr(output_buf, "\n");
2308
 
    }
2309
 
#if SVN_DEBUG
2310
 
  else if (!mergeinfo)
2311
 
    {
2312
 
      output_buf = svn_stringbuf_create(prefix ? prefix : "", pool);
2313
 
      svn_stringbuf_appendcstr(output_buf, _("NULL mergeinfo\n"));
2314
 
    }
2315
 
  else if (apr_hash_count(mergeinfo) == 0)
2316
 
    {
2317
 
      output_buf = svn_stringbuf_create(prefix ? prefix : "", pool);
2318
 
      svn_stringbuf_appendcstr(output_buf, _("empty mergeinfo\n"));
2319
 
    }
2320
 
#endif
2321
 
 
2322
 
  *output = output_buf ? svn_stringbuf__morph_into_string(output_buf)
2323
 
                       : svn_string_create("", pool);
2324
 
  return SVN_NO_ERROR;
2325
 
}
2326
 
 
2327
 
svn_error_t *
2328
2322
svn_mergeinfo__get_range_endpoints(svn_revnum_t *youngest_rev,
2329
2323
                                   svn_revnum_t *oldest_rev,
2330
2324
                                   svn_mergeinfo_t mergeinfo,
2337
2331
 
2338
2332
      for (hi = apr_hash_first(pool, mergeinfo); hi; hi = apr_hash_next(hi))
2339
2333
        {
2340
 
          apr_array_header_t *rangelist = svn__apr_hash_index_val(hi);
 
2334
          svn_rangelist_t *rangelist = svn__apr_hash_index_val(hi);
2341
2335
 
2342
2336
          if (rangelist->nelts)
2343
2337
            {
2386
2380
                                                        result_pool,
2387
2381
                                                        scratch_pool));
2388
2382
      if (apr_hash_count(filtered_mergeinfo))
2389
 
        apr_hash_set(*filtered_cat,
2390
 
                     apr_pstrdup(result_pool, path),
2391
 
                     APR_HASH_KEY_STRING,
2392
 
                     filtered_mergeinfo);
 
2383
        svn_hash_sets(*filtered_cat,
 
2384
                      apr_pstrdup(result_pool, path), filtered_mergeinfo);
2393
2385
    }
2394
2386
 
2395
2387
  return SVN_NO_ERROR;
2413
2405
  if (mergeinfo)
2414
2406
    {
2415
2407
      apr_hash_index_t *hi;
2416
 
      apr_array_header_t *filter_rangelist =
 
2408
      svn_rangelist_t *filter_rangelist =
2417
2409
        svn_rangelist__initialize(oldest_rev, youngest_rev, TRUE,
2418
2410
                                  scratch_pool);
2419
2411
 
2422
2414
           hi = apr_hash_next(hi))
2423
2415
        {
2424
2416
          const char *path = svn__apr_hash_index_key(hi);
2425
 
          apr_array_header_t *rangelist = svn__apr_hash_index_val(hi);
 
2417
          svn_rangelist_t *rangelist = svn__apr_hash_index_val(hi);
2426
2418
 
2427
2419
          if (rangelist->nelts)
2428
2420
            {
2429
 
              apr_array_header_t *new_rangelist;
 
2421
              svn_rangelist_t *new_rangelist;
2430
2422
 
2431
2423
              SVN_ERR(rangelist_intersect_or_remove(
2432
2424
                        &new_rangelist, filter_rangelist, rangelist,
2433
2425
                        ! include_range, FALSE, result_pool));
2434
2426
 
2435
2427
              if (new_rangelist->nelts)
2436
 
                apr_hash_set(*filtered_mergeinfo,
2437
 
                             apr_pstrdup(result_pool, path),
2438
 
                             APR_HASH_KEY_STRING,
2439
 
                             new_rangelist);
 
2428
                svn_hash_sets(*filtered_mergeinfo,
 
2429
                              apr_pstrdup(result_pool, path), new_rangelist);
2440
2430
            }
2441
2431
        }
2442
2432
    }
2461
2451
        {
2462
2452
          int i;
2463
2453
          const char *path = svn__apr_hash_index_key(hi);
2464
 
          apr_array_header_t *rangelist = svn__apr_hash_index_val(hi);
2465
 
          apr_array_header_t *adjusted_rangelist =
 
2454
          svn_rangelist_t *rangelist = svn__apr_hash_index_val(hi);
 
2455
          svn_rangelist_t *adjusted_rangelist =
2466
2456
            apr_array_make(result_pool, rangelist->nelts,
2467
2457
                           sizeof(svn_merge_range_t *));
2468
2458
 
2488
2478
            }
2489
2479
 
2490
2480
          if (adjusted_rangelist->nelts)
2491
 
            apr_hash_set(*adjusted_mergeinfo, apr_pstrdup(result_pool, path),
2492
 
                         APR_HASH_KEY_STRING, adjusted_rangelist);
 
2481
            svn_hash_sets(*adjusted_mergeinfo, apr_pstrdup(result_pool, path),
 
2482
                          adjusted_rangelist);
2493
2483
        }
2494
2484
    }
2495
2485
  return SVN_NO_ERROR;
2507
2497
           hi;
2508
2498
           hi = apr_hash_next(hi))
2509
2499
        {
2510
 
          apr_array_header_t *rangelist = svn__apr_hash_index_val(hi);
 
2500
          svn_rangelist_t *rangelist = svn__apr_hash_index_val(hi);
2511
2501
          int i;
2512
2502
 
2513
2503
          for (i = 0; i < rangelist->nelts; i++)
2522
2512
  return FALSE;
2523
2513
}
2524
2514
 
2525
 
svn_error_t *
2526
 
svn_mergeinfo__string_has_noninheritable(svn_boolean_t *is_noninheritable,
2527
 
                                         const char *mergeinfo_str,
2528
 
                                         apr_pool_t *scratch_pool)
2529
 
{
2530
 
  *is_noninheritable = FALSE;
2531
 
 
2532
 
  if (mergeinfo_str)
2533
 
    {
2534
 
      svn_mergeinfo_t mergeinfo;
2535
 
 
2536
 
      SVN_ERR(svn_mergeinfo_parse(&mergeinfo, mergeinfo_str, scratch_pool));
2537
 
      *is_noninheritable = svn_mergeinfo__is_noninheritable(mergeinfo,
2538
 
                                                            scratch_pool);
2539
 
    }
2540
 
 
2541
 
  return SVN_NO_ERROR;
2542
 
}
2543
 
 
2544
 
apr_array_header_t *
 
2515
svn_rangelist_t *
2545
2516
svn_rangelist__initialize(svn_revnum_t start,
2546
2517
                          svn_revnum_t end,
2547
2518
                          svn_boolean_t inheritable,
2548
2519
                          apr_pool_t *result_pool)
2549
2520
{
2550
 
  apr_array_header_t *rangelist =
 
2521
  svn_rangelist_t *rangelist =
2551
2522
    apr_array_make(result_pool, 1, sizeof(svn_merge_range_t *));
2552
2523
  svn_merge_range_t *range = apr_pcalloc(result_pool, sizeof(*range));
2553
2524
 
2571
2542
    {
2572
2543
      svn_location_segment_t *segment =
2573
2544
        APR_ARRAY_IDX(segments, i, svn_location_segment_t *);
2574
 
      apr_array_header_t *path_ranges;
 
2545
      svn_rangelist_t *path_ranges;
2575
2546
      svn_merge_range_t *range;
2576
2547
      const char *source_path;
2577
2548
 
2584
2555
 
2585
2556
      /* See if we already stored ranges for this path.  If not, make
2586
2557
         a new list.  */
2587
 
      path_ranges = apr_hash_get(mergeinfo, source_path, APR_HASH_KEY_STRING);
 
2558
      path_ranges = svn_hash_gets(mergeinfo, source_path);
2588
2559
      if (! path_ranges)
2589
2560
        path_ranges = apr_array_make(pool, 1, sizeof(range));
2590
2561
 
2601
2572
      range->end = segment->range_end;
2602
2573
      range->inheritable = TRUE;
2603
2574
      APR_ARRAY_PUSH(path_ranges, svn_merge_range_t *) = range;
2604
 
      apr_hash_set(mergeinfo, source_path, APR_HASH_KEY_STRING, path_ranges);
 
2575
      svn_hash_sets(mergeinfo, source_path, path_ranges);
2605
2576
    }
2606
2577
 
2607
2578
  *mergeinfo_p = mergeinfo;
2608
2579
  return SVN_NO_ERROR;
2609
2580
}
 
2581
 
 
2582
svn_error_t *
 
2583
svn_rangelist__merge_many(svn_rangelist_t *merged_rangelist,
 
2584
                          svn_mergeinfo_t merge_history,
 
2585
                          apr_pool_t *result_pool,
 
2586
                          apr_pool_t *scratch_pool)
 
2587
{
 
2588
  if (apr_hash_count(merge_history))
 
2589
    {
 
2590
      apr_pool_t *iterpool = svn_pool_create(scratch_pool);
 
2591
      apr_hash_index_t *hi;
 
2592
 
 
2593
      for (hi = apr_hash_first(scratch_pool, merge_history);
 
2594
           hi;
 
2595
           hi = apr_hash_next(hi))
 
2596
        {
 
2597
          svn_rangelist_t *subtree_rangelist = svn__apr_hash_index_val(hi);
 
2598
 
 
2599
          svn_pool_clear(iterpool);
 
2600
          SVN_ERR(svn_rangelist_merge2(merged_rangelist, subtree_rangelist,
 
2601
                                       result_pool, iterpool));
 
2602
        }
 
2603
      svn_pool_destroy(iterpool);
 
2604
    }
 
2605
  return SVN_NO_ERROR;
 
2606
}
 
2607
 
 
2608
 
 
2609
const char *
 
2610
svn_inheritance_to_word(svn_mergeinfo_inheritance_t inherit)
 
2611
{
 
2612
  switch (inherit)
 
2613
    {
 
2614
    case svn_mergeinfo_inherited:
 
2615
      return "inherited";
 
2616
    case svn_mergeinfo_nearest_ancestor:
 
2617
      return "nearest-ancestor";
 
2618
    default:
 
2619
      return "explicit";
 
2620
    }
 
2621
}
 
2622
 
 
2623
svn_mergeinfo_inheritance_t
 
2624
svn_inheritance_from_word(const char *word)
 
2625
{
 
2626
  if (strcmp(word, "inherited") == 0)
 
2627
    return svn_mergeinfo_inherited;
 
2628
  if (strcmp(word, "nearest-ancestor") == 0)
 
2629
    return svn_mergeinfo_nearest_ancestor;
 
2630
  return svn_mergeinfo_explicit;
 
2631
}