Modified: subversion/branches/addremove/subversion/libsvn_subr/iter.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_subr/iter.c?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/libsvn_subr/iter.c (original)
+++ subversion/branches/addremove/subversion/libsvn_subr/iter.c Sat May 23 
14:16:56 2020
@@ -37,7 +37,6 @@ static svn_error_t internal_break_error
     __LINE__ /* line number */
   };
 
-#if APR_VERSION_AT_LEAST(1, 4, 0)
 struct hash_do_baton
 {
   void *baton;
@@ -59,7 +58,6 @@ int hash_do_callback(void *baton,
 
   return hdb->err == SVN_NO_ERROR;
 }
-#endif
 
 svn_error_t *
 svn_iter_apr_hash(svn_boolean_t *completed,
@@ -68,7 +66,6 @@ svn_iter_apr_hash(svn_boolean_t *complet
                   void *baton,
                   apr_pool_t *pool)
 {
-#if APR_VERSION_AT_LEAST(1, 4, 0)
   struct hash_do_baton hdb;
   svn_boolean_t error_received;
 
@@ -97,43 +94,6 @@ svn_iter_apr_hash(svn_boolean_t *complet
     }
 
   return hdb.err;
-#else
-  svn_error_t *err = SVN_NO_ERROR;
-  apr_pool_t *iterpool = svn_pool_create(pool);
-  apr_hash_index_t *hi;
-
-  for (hi = apr_hash_first(pool, hash);
-       ! err && hi; hi = apr_hash_next(hi))
-    {
-      const void *key;
-      void *val;
-      apr_ssize_t len;
-
-      svn_pool_clear(iterpool);
-
-      apr_hash_this(hi, &key, &len, &val);
-      err = (*func)(baton, key, len, val, iterpool);
-    }
-
-  if (completed)
-    *completed = ! err;
-
-  if (err && err->apr_err == SVN_ERR_ITER_BREAK)
-    {
-      if (err != &internal_break_error)
-        /* Errors - except those created by svn_iter_break() -
-           need to be cleared when not further propagated. */
-        svn_error_clear(err);
-
-      err = SVN_NO_ERROR;
-    }
-
-  /* Clear iterpool, because callers may clear the error but have no way
-     to clear the iterpool with potentially lots of allocated memory */
-  svn_pool_destroy(iterpool);
-
-  return err;
-#endif
 }
 
 svn_error_t *
@@ -183,29 +143,3 @@ svn_iter__break(void)
 {
   return &internal_break_error;
 }
-
-#if !APR_VERSION_AT_LEAST(1, 5, 0)
-const void *apr_hash_this_key(apr_hash_index_t *hi)
-{
-  const void *key;
-
-  apr_hash_this((apr_hash_index_t *)hi, &key, NULL, NULL);
-  return key;
-}
-
-apr_ssize_t apr_hash_this_key_len(apr_hash_index_t *hi)
-{
-  apr_ssize_t klen;
-
-  apr_hash_this((apr_hash_index_t *)hi, NULL, &klen, NULL);
-  return klen;
-}
-
-void *apr_hash_this_val(apr_hash_index_t *hi)
-{
-  void *val;
-
-  apr_hash_this((apr_hash_index_t *)hi, NULL, NULL, &val);
-  return val;
-}
-#endif

Propchange: subversion/branches/addremove/subversion/libsvn_subr/lz4/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Sat May 23 14:16:56 2020
@@ -0,0 +1 @@
+.libs

Modified: subversion/branches/addremove/subversion/libsvn_subr/lz4/lz4.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_subr/lz4/lz4.c?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/libsvn_subr/lz4/lz4.c (original)
+++ subversion/branches/addremove/subversion/libsvn_subr/lz4/lz4.c Sat May 23 
14:16:56 2020
@@ -1,5 +1,5 @@
 #include "svn_private_config.h"
-#if SVN_INTERNAL_LZ4
+#ifdef SVN_INTERNAL_LZ4
 /*
    LZ4 - Fast LZ compression algorithm
    Copyright (C) 2011-2016, Yann Collet.
@@ -1471,4 +1471,11 @@ int LZ4_decompress_fast_withPrefix64k(co
 }
 
 #endif   /* LZ4_COMMONDEFS_ONLY */
+#else /* !SVN_INTERNAL_LZ4 */
+
+/* Silence OSX ranlib warnings about object files with no symbols. */
+#include <apr.h>
+extern const apr_uint32_t svn__fake__lz4internal;
+const apr_uint32_t svn__fake__lz4internal = 0xdeadbeef;
+
 #endif /* SVN_INTERNAL_LZ4 */

Modified: subversion/branches/addremove/subversion/libsvn_subr/lz4/lz4internal.h
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_subr/lz4/lz4internal.h?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/libsvn_subr/lz4/lz4internal.h 
(original)
+++ subversion/branches/addremove/subversion/libsvn_subr/lz4/lz4internal.h Sat 
May 23 14:16:56 2020
@@ -1,5 +1,5 @@
 #include "svn_private_config.h"
-#if SVN_INTERNAL_LZ4
+#ifdef SVN_INTERNAL_LZ4
 /*
  *  LZ4 - Fast LZ compression algorithm
  *  Header File

Modified: subversion/branches/addremove/subversion/libsvn_subr/mergeinfo.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_subr/mergeinfo.c?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/libsvn_subr/mergeinfo.c (original)
+++ subversion/branches/addremove/subversion/libsvn_subr/mergeinfo.c Sat May 23 
14:16:56 2020
@@ -44,8 +44,9 @@
 /* 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,
+static svn_error_t *
+range_contains(svn_boolean_t *result,
+               const svn_merge_range_t *first, const svn_merge_range_t *second,
                svn_boolean_t consider_inheritance);
 
 
@@ -457,21 +458,48 @@ combine_with_lastrange(const svn_merge_r
 }
 
 /* Convert a single svn_merge_range_t *RANGE back into a string.  */
-static char *
-range_to_string(const svn_merge_range_t *range,
+static svn_error_t *
+range_to_string(char **s,
+                const svn_merge_range_t *range,
                 apr_pool_t *pool)
 {
   const char *mark
     = range->inheritable ? "" : SVN_MERGEINFO_NONINHERITABLE_STR;
 
   if (range->start == range->end - 1)
-    return apr_psprintf(pool, "%ld%s", range->end, mark);
+    *s = apr_psprintf(pool, "%ld%s", range->end, mark);
   else if (range->start - 1 == range->end)
-    return apr_psprintf(pool, "-%ld%s", range->start, mark);
+    *s = apr_psprintf(pool, "-%ld%s", range->start, mark);
   else if (range->start < range->end)
-    return apr_psprintf(pool, "%ld-%ld%s", range->start + 1, range->end, mark);
+    *s = apr_psprintf(pool, "%ld-%ld%s", range->start + 1, range->end, mark);
+  else if (range->start > range->end)
+    *s = apr_psprintf(pool, "%ld-%ld%s", range->start, range->end + 1, mark);
   else
-    return apr_psprintf(pool, "%ld-%ld%s", range->start, range->end + 1, mark);
+    {
+      return svn_error_createf(SVN_ERR_ASSERTION_FAIL, NULL,
+                               _("bad range 
{start=%ld,end=%ld,inheritable=%d}"),
+                               range->start, range->end, range->inheritable);
+    }
+
+  return SVN_NO_ERROR;
+}
+
+/* Convert a single svn_merge_range_t *RANGE back into a string.  */
+static char *
+range_to_string_debug(const svn_merge_range_t *range,
+                      apr_pool_t *pool)
+{
+  svn_error_t *err;
+  char *s;
+
+  err = range_to_string(&s, range, pool);
+  if (err)
+    {
+      svn_error_clear(err);
+      s = apr_psprintf(pool, _("bad range {start=%ld,end=%ld,inheritable=%d}"),
+                       range->start, range->end, range->inheritable);
+    }
+  return s;
 }
 
 /* Helper for svn_mergeinfo_parse()
@@ -667,10 +695,10 @@ svn_rangelist__canonicalize(svn_rangelis
                                          "revision ranges '%s' and '%s' "
                                          "with different inheritance "
                                          "types"),
-                                       range_to_string(lastrange,
-                                                       scratch_pool),
-                                       range_to_string(range,
-                                                       scratch_pool));
+                                       range_to_string_debug(lastrange,
+                                                             scratch_pool),
+                                       range_to_string_debug(range,
+                                                             scratch_pool));
             }
 
           /* Combine overlapping or adjacent ranges with the
@@ -678,7 +706,7 @@ svn_rangelist__canonicalize(svn_rangelis
           if (lastrange->inheritable == range->inheritable)
             {
               lastrange->end = MAX(range->end, lastrange->end);
-              svn_sort__array_delete(rangelist, i, 1);
+              SVN_ERR(svn_sort__array_delete2(rangelist, i, 1));
               i--;
             }
         }
@@ -788,490 +816,349 @@ svn_mergeinfo_parse(svn_mergeinfo_t *mer
   return err;
 }
 
-/* Cleanup after svn_rangelist_merge2 when it modifies the ending range of
-   a single rangelist element in-place.
-
-   If *RANGE_INDEX is not a valid element in RANGELIST do nothing.  Otherwise
-   ensure that RANGELIST[*RANGE_INDEX]->END does not adjoin or overlap any
-   subsequent ranges in RANGELIST.
-
-   If overlap is found, then remove, modify, and/or add elements to RANGELIST
-   as per the invariants for rangelists documented in svn_mergeinfo.h.  If
-   RANGELIST[*RANGE_INDEX]->END adjoins a subsequent element then combine the
-   elements if their inheritability permits -- The inheritance of intersecting
-   and adjoining ranges is handled as per svn_mergeinfo_merge2.  Upon return
-   set *RANGE_INDEX to the index of the youngest element modified, added, or
-   adjoined to RANGELIST[*RANGE_INDEX].
+static const char *
+rangelist_to_string_debug(const svn_rangelist_t *rl,
+                          apr_pool_t *pool)
+{
+  svn_string_t *rls;
+  svn_error_t *err;
 
-   Note: Adjoining rangelist elements are those where the end rev of the older
-   element is equal to the start rev of the younger element.
+  err = svn_rangelist_to_string(&rls, rl, pool);
+  if (err)
+    {
+      char *s = apr_psprintf(pool, _("<bad rangelist [%d ranges]: %s>"),
+                             rl->nelts, err->message);
+      svn_error_clear(err);
+      return s;
+    }
+  return rls->data;
+}
 
-   Any new elements inserted into RANGELIST are allocated in  RESULT_POOL.*/
-static void
-adjust_remaining_ranges(svn_rangelist_t *rangelist,
-                        int *range_index,
-                        apr_pool_t *result_pool)
+static svn_boolean_t
+rangelist_is_sorted(const svn_rangelist_t *rangelist)
 {
   int i;
-  int starting_index;
-  int elements_to_delete = 0;
-  svn_merge_range_t *modified_range;
-
-  if (*range_index >= rangelist->nelts)
-    return;
 
-  starting_index = *range_index + 1;
-  modified_range = APR_ARRAY_IDX(rangelist, *range_index, svn_merge_range_t *);
-
-  for (i = *range_index + 1; i < rangelist->nelts; i++)
+  for (i = 1; i < rangelist->nelts; i++)
     {
-      svn_merge_range_t *next_range = APR_ARRAY_IDX(rangelist, i,
-                                                    svn_merge_range_t *);
+      const svn_merge_range_t *lastrange
+        = APR_ARRAY_IDX(rangelist, i-1, svn_merge_range_t *);
+      const svn_merge_range_t *thisrange
+        = APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *);
 
-      /* If MODIFIED_RANGE doesn't adjoin or overlap the next range in
-         RANGELIST then we are finished. */
-      if (modified_range->end < next_range->start)
-        break;
+      if (svn_sort_compare_ranges(&lastrange, &thisrange) > 0)
+        return FALSE;
+    }
+  return TRUE;
+}
 
-      /* Does MODIFIED_RANGE adjoin NEXT_RANGE? */
-      if (modified_range->end == next_range->start)
-        {
-          if (modified_range->inheritable == next_range->inheritable)
-            {
-              /* Combine adjoining ranges with the same inheritability. */
-              modified_range->end = next_range->end;
-              elements_to_delete++;
-            }
-          else
-            {
-              /* Cannot join because inheritance differs. */
-              (*range_index)++;
-            }
-          break;
-        }
+/* Mergeinfo inheritance or absence in a rangelist interval */
+enum rangelist_interval_kind_t { MI_NONE, MI_NON_INHERITABLE, MI_INHERITABLE };
 
-      /* Alright, we know MODIFIED_RANGE overlaps NEXT_RANGE, but how? */
-      if (modified_range->end > next_range->end)
-        {
-          /* NEXT_RANGE is a proper subset of MODIFIED_RANGE and the two
-             don't share the same end range. */
-          if (modified_range->inheritable
-              || (modified_range->inheritable == next_range->inheritable))
-            {
-              /* MODIFIED_RANGE absorbs NEXT_RANGE. */
-              elements_to_delete++;
-            }
-          else
-            {
-              /* NEXT_RANGE is a proper subset MODIFIED_RANGE but
-                 MODIFIED_RANGE is non-inheritable and NEXT_RANGE is
-                 inheritable.  This means MODIFIED_RANGE is truncated,
-                 NEXT_RANGE remains, and the portion of MODIFIED_RANGE
-                 younger than NEXT_RANGE is added as a separate range:
-                  ______________________________________________
-                 |                                              |
-                 M                 MODIFIED_RANGE               N
-                 |                 (!inheritable)               |
-                 |______________________________________________|
-                                  |              |
-                                  O  NEXT_RANGE  P
-                                  | (inheritable)|
-                                  |______________|
-                                         |
-                                         V
-                  _______________________________________________
-                 |                |              |               |
-                 M MODIFIED_RANGE O  NEXT_RANGE  P   NEW_RANGE   N
-                 | (!inheritable) | (inheritable)| (!inheritable)|
-                 |________________|______________|_______________|
-              */
-              svn_merge_range_t *new_modified_range =
-                apr_palloc(result_pool, sizeof(*new_modified_range));
-              new_modified_range->start = next_range->end;
-              new_modified_range->end = modified_range->end;
-              new_modified_range->inheritable = FALSE;
-              modified_range->end = next_range->start;
-              (*range_index)+=2;
-              svn_sort__array_insert(rangelist, &new_modified_range,
-                                     *range_index);
-              /* Recurse with the new range. */
-              adjust_remaining_ranges(rangelist, range_index, result_pool);
-              break;
-            }
-        }
-      else if (modified_range->end == next_range->end)
-        {
-          /* NEXT_RANGE is a proper subset MODIFIED_RANGE and share
-             the same end range. */
-          if (modified_range->inheritable
-              || (modified_range->inheritable == next_range->inheritable))
-            {
-              /* MODIFIED_RANGE absorbs NEXT_RANGE. */
-              elements_to_delete++;
-            }
-          else
-            {
-              /* The intersection between MODIFIED_RANGE and NEXT_RANGE is
-                 absorbed by the latter. */
-              modified_range->end = next_range->start;
-              (*range_index)++;
-            }
-          break;
-        }
-      else
-        {
-          /* NEXT_RANGE and MODIFIED_RANGE intersect but NEXT_RANGE is not
-             a proper subset of MODIFIED_RANGE, nor do the two share the
-             same end revision, i.e. they overlap. */
-          if (modified_range->inheritable == next_range->inheritable)
-            {
-              /* Combine overlapping ranges with the same inheritability. */
-              modified_range->end = next_range->end;
-              elements_to_delete++;
-            }
-          else if (modified_range->inheritable)
-            {
-              /* MODIFIED_RANGE absorbs the portion of NEXT_RANGE it overlaps
-                 and NEXT_RANGE is truncated. */
-              next_range->start = modified_range->end;
-              (*range_index)++;
-            }
-          else
-            {
-              /* NEXT_RANGE absorbs the portion of MODIFIED_RANGE it overlaps
-                 and MODIFIED_RANGE is truncated. */
-              modified_range->end = next_range->start;
-              (*range_index)++;
-            }
-          break;
-        }
+/* A rangelist interval: like svn_merge_range_t but an interval can represent
+ * a gap in the rangelist (kind = MI_NONE). */
+typedef struct rangelist_interval_t
+{
+  svn_revnum_t start, end;
+  enum rangelist_interval_kind_t kind;
+} rangelist_interval_t;
+
+/* Iterator for intervals in a rangelist. */
+typedef struct rangelist_interval_iterator_t {
+  /* iteration state: */
+  const svn_rangelist_t *rl;  /* input */
+  int i;  /* current interval is this range in RL or the gap before it */
+  svn_boolean_t in_range;  /* current interval is range RL[I], not a gap? */
+
+  /* current interval: */
+  rangelist_interval_t interval;
+} rangelist_interval_iterator_t;
+
+/* Update IT->interval to match the current iteration state of IT.
+ * Return the iterator, or NULL if the iteration has reached its end.
+ */
+static rangelist_interval_iterator_t *
+rlii_update(rangelist_interval_iterator_t *it)
+{
+  const svn_merge_range_t *range
+    = (it->i < it->rl->nelts
+       ? APR_ARRAY_IDX(it->rl, it->i, void *) : NULL);
+
+  if (!range)
+    return NULL;
+
+  if (!it->in_range)
+    {
+      it->interval.start
+        = (it->i > 0
+           ? APR_ARRAY_IDX(it->rl, it->i - 1, svn_merge_range_t *)->end
+           : 0);
+      it->interval.end = range->start;
+      it->interval.kind = MI_NONE;
+    }
+  else
+    {
+      it->interval.start = range->start;
+      it->interval.end = range->end;
+      it->interval.kind
+        = (range->inheritable ? MI_INHERITABLE : MI_NON_INHERITABLE);
     }
+  return it;
+}
 
-  if (elements_to_delete)
-    svn_sort__array_delete(rangelist, starting_index, elements_to_delete);
+/* Move to the next interval, which might be a zero-length interval.
+ * Return IT, or return NULL at the end of iteration. */
+static rangelist_interval_iterator_t *
+rlii_next_any_interval(rangelist_interval_iterator_t *it)
+{
+  /* Should be called before iteration is finished. */
+  if (it->i >= it->rl->nelts)
+    return NULL;
+
+  /* If we are in a range, move to the next pre-range gap;
+   * else, move from this pre-range gap into this range. */
+  if (it->in_range)
+    it->i++;
+  it->in_range = !it->in_range;
+  return it;
 }
 
-#if 0 /* Temporary debug helper code */
-static svn_error_t *
-dual_dump(const char *prefix,
-  const svn_rangelist_t *rangelist,
-  const svn_rangelist_t *changes,
-  apr_pool_t *scratch_pool)
+/* Return an iterator pointing at the first non-zero-length interval in RL,
+ * or NULL if there are none. */
+static rangelist_interval_iterator_t *
+rlii_first(const svn_rangelist_t *rl,
+           apr_pool_t *pool)
 {
-  svn_string_t *rls, *chg;
+  rangelist_interval_iterator_t *it = apr_palloc(pool, sizeof(*it));
 
-  SVN_ERR(svn_rangelist_to_string(&rls, rangelist, scratch_pool));
-  SVN_ERR(svn_rangelist_to_string(&chg, changes, scratch_pool));
+  it->rl = rl;
+  it->i = 0;
+  it->in_range = FALSE;
 
-  SVN_DBG(("%s: %s / %s", prefix, rls->data, chg->data));
-  return SVN_NO_ERROR;
+  /* Update, and skip empty intervals */
+  while ((it = rlii_update(it)) && it->interval.start == it->interval.end)
+    {
+      it = rlii_next_any_interval(it);
+    }
+  return it;
 }
-#endif
 
-svn_error_t *
-svn_rangelist_merge2(svn_rangelist_t *rangelist,
-                     const svn_rangelist_t *chg,
-                     apr_pool_t *result_pool,
-                     apr_pool_t *scratch_pool)
+/* Move to the next non-empty interval.
+ * Intervals will be generated in this sequence:
+ *  (0,               MI_NONE,  RL[0]->start),  // i=0, !in_range
+ *  (RL[0]->start,    MI_*      RL[0]->end),    // i=0, in_range
+ *  (RL[0]->end,      MI_NONE,  RL[1]->start),
+ *  (RL[1]->start,    MI_*      RL[1]->end),
+ *  ...
+ *  (RL[n-2]->end,    MI_NONE,  RL[n-1]->start),
+ *  (RL[n-1]->start,  MI_*      RL[n-1]->end),
+ * but excluding empty intervals.
+ * Return IT, or return NULL at the end of iteration. */
+static rangelist_interval_iterator_t *
+rlii_next(rangelist_interval_iterator_t *it)
 {
-  svn_rangelist_t *changes;
-  int i = 0;
-  int j;
+  it = rlii_next_any_interval(it);
 
-  SVN_ERR(svn_rangelist__canonicalize(rangelist, scratch_pool));
+  /* Update, and skip empty intervals */
+  while ((it = rlii_update(it)) && it->interval.start == it->interval.end)
+    {
+      it = rlii_next_any_interval(it);
+    }
+  return it;
+}
 
-  /* We may modify CHANGES, so make a copy in SCRATCH_POOL. */
-  changes = svn_rangelist_dup(chg, scratch_pool);
-  SVN_ERR(svn_rangelist__canonicalize(changes, scratch_pool));
+/* Rangelist builder. Accumulates consecutive intervals, combining them
+ * when possible. */
+typedef struct rangelist_builder_t {
+  svn_rangelist_t *rl;  /* rangelist to build */
+  rangelist_interval_t accu_interval;  /* current interval accumulator */
+  apr_pool_t *pool;  /* from which to allocate ranges */
+} rangelist_builder_t;
 
-  for (j = 0; j < changes->nelts; j++)
-    {
-      svn_merge_range_t *range;
-      svn_merge_range_t *change =
-        APR_ARRAY_IDX(changes, j, svn_merge_range_t *);
-      int res;
+/* Return an initialized rangelist builder. */
+static rangelist_builder_t *
+rl_builder_new(svn_rangelist_t *rl,
+               apr_pool_t *pool)
+{
+  rangelist_builder_t *b = apr_pcalloc(pool, sizeof(*b));
 
-      range = (i < rangelist->nelts)
-              ? APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *)
-              : NULL;
-
-      if (!range || change->end < range->start)
-        {
-          /* No overlap, nor adjoin, copy change to result range */
-          svn_merge_range_t *chg_copy = svn_merge_range_dup(change,
-                                                            result_pool);
-          svn_sort__array_insert(rangelist, &chg_copy, i++);
-          continue;
-        }
-      else if ((change->start > range->end)
-               || (change->start == range->end
-                   && change->inheritable != range->inheritable))
-        {
-          /* No overlap, nor adjoin. Check next range item against change */
-          i++;
-          j--;
-          continue;
-        }
+  b->rl = rl;
+  /* b->accu_interval = {0, 0, RL_NONE} */
+  b->pool = pool;
+  return b;
+}
 
-      if (change->start < range->start
-          && range->inheritable != change->inheritable
-          && ! (change->inheritable && range_contains(change, range, FALSE))
-          && ! (range->inheritable && range_contains(range, change, FALSE)))
-        {
-          /* Can't fold change into existing range.
-             Insert new range before range */
+/* Flush the last accumulated interval in the rangelist builder B. */
+static void
+rl_builder_flush(rangelist_builder_t *b)
+{
+  if (b->accu_interval.kind > MI_NONE)
+    {
+      svn_merge_range_t *mrange = apr_pcalloc(b->pool, sizeof(*mrange));
+      mrange->start = b->accu_interval.start;
+      mrange->end = b->accu_interval.end;
+      mrange->inheritable = (b->accu_interval.kind == MI_INHERITABLE);
+      APR_ARRAY_PUSH(b->rl, svn_merge_range_t *) = mrange;
+    }
+}
 
-          svn_merge_range_t *chg_copy = svn_merge_range_dup(change,
-                                                            result_pool);
+/* Add a new INTERVAL to the rangelist builder B. */
+static void
+rl_builder_add_interval(rangelist_builder_t *b,
+                        const rangelist_interval_t *interval)
+{
+  SVN_ERR_ASSERT_NO_RETURN(interval->start < interval->end);
+  SVN_ERR_ASSERT_NO_RETURN(interval->start == b->accu_interval.end);
 
-          chg_copy->start = MIN(change->start, range->start);
-          if (! change->inheritable)
-            chg_copy->end = range->start;
-          else
-            range->start = change->end;
+  /* Extend the accumulating interval, or end it and start another? */
+  if (interval->kind == b->accu_interval.kind)
+    {
+      b->accu_interval.end = interval->end;
+    }
+  else
+    {
+      /* Push the accumulated interval onto the building rangelist. */
+      rl_builder_flush(b);
+      /* Start accumulating a new interval */
+      b->accu_interval = *interval;
+    }
+}
 
-          svn_sort__array_insert(rangelist, &chg_copy, i++);
+/* Set RL_OUT to the union (merge) of RL1 and RL2.
+ * On entry, RL_OUT must be an empty rangelist.
+ *
+ * Each range added to RL_OUT will be either shallow-copied from RL1 or
+ * allocated from RESULT_POOL.
+ */
+static svn_error_t *
+rangelist_merge(svn_rangelist_t *rl_out,
+                const svn_rangelist_t *rl1,
+                const svn_rangelist_t *rl2,
+                apr_pool_t *result_pool,
+                apr_pool_t *scratch_pool)
+{
+  rangelist_interval_iterator_t *it[2];
+  rangelist_builder_t *rl_builder = rl_builder_new(rl_out, result_pool);
+  svn_revnum_t r_last = 0;
+
+  /*SVN_ERR_ASSERT(svn_rangelist__is_canonical(rl1));*/
+  /*SVN_ERR_ASSERT(svn_rangelist__is_canonical(rl2));*/
+  SVN_ERR_ASSERT(rangelist_is_sorted(rl1));
+  SVN_ERR_ASSERT(rangelist_is_sorted(rl2));
+  SVN_ERR_ASSERT(rl_out->nelts == 0);
+
+  /* Initialize the input iterators and the output generator */
+  it[0] = rlii_first(rl1, scratch_pool);
+  it[1] = rlii_first(rl2, scratch_pool);
+
+  /* Keep choosing the next input revision (whether a start or end of a range)
+   * at which to consider making an output transition. */
+  while (it[0] || it[1])
+    {
+      svn_revnum_t r_next = !it[1] ? it[0]->interval.end
+                            : !it[0] ? it[1]->interval.end
+                            : MIN(it[0]->interval.end, it[1]->interval.end);
+      rangelist_interval_t interval;
+
+      interval.start = r_last;
+      interval.end = r_next;
+      interval.kind = !it[1] ? it[0]->interval.kind
+                       : !it[0] ? it[1]->interval.kind
+                       : MAX(it[0]->interval.kind, it[1]->interval.kind);
+
+      /* Accumulate */
+      SVN_ERR_ASSERT(interval.start < interval.end);
+      rl_builder_add_interval(rl_builder, &interval);
+
+      /* if we have used up either or both input intervals, increment them */
+      if (it[0] && it[0]->interval.end <= r_next)
+        it[0] = rlii_next(it[0]);
+      if (it[1] && it[1]->interval.end <= r_next)
+        it[1] = rlii_next(it[1]);
 
-          change->start = chg_copy->end;
-          if (change->start >= change->end)
-            continue; /* No overlap with range left */
-        }
-      else
-        {
-          range->start = MIN(range->start, change->start);
-        }
+      r_last = interval.end;
+    }
+  rl_builder_flush(rl_builder);
+  return SVN_NO_ERROR;
+}
 
-      SVN_ERR_ASSERT(change->start >= range->start);
+svn_error_t *
+svn_rangelist_merge2(svn_rangelist_t *rangelist,
+                     const svn_rangelist_t *chg,
+                     apr_pool_t *result_pool,
+                     apr_pool_t *scratch_pool)
+{
+  svn_error_t *err;
+  svn_rangelist_t *rangelist_orig;
 
-      res = svn_sort_compare_ranges(&range, &change);
+#ifdef SVN_DEBUG
+  SVN_ERR_ASSERT(rangelist_is_sorted(rangelist));
+  SVN_ERR_ASSERT(rangelist_is_sorted(chg));
+#endif
 
-      if (res == 0)
-        {
-          /* Only when merging two non-inheritable ranges is the result also
-             non-inheritable.  In all other cases ensure an inheritable
-             result. */
-          if (range->inheritable || change->inheritable)
-            range->inheritable = TRUE;
-          i++;
-          continue;
-        }
-      else if (res < 0) /* CHANGE is younger than RANGE */
-        {
-          if (range->end == change->start)
-            {
-              /* RANGE and CHANGE adjoin */
-              if (range->inheritable == change->inheritable)
-                {
-                  /* RANGE and CHANGE have the same inheritability so
-                     RANGE expands to absord CHANGE. */
-                  range->end = change->end;
-                  adjust_remaining_ranges(rangelist, &i, result_pool);
-                  continue;
-                }
-              else
-                {
-                  /* RANGE and CHANGE adjoin, but have different
-                     inheritability.  Since RANGE is older, just
-                     move on to the next RANGE. */
-                  SVN_ERR_MALFUNCTION();
-                }
-            }
-          else
-            {
-              /* RANGE and CHANGE overlap, but how? */
-              if ((range->inheritable == change->inheritable)
-                  || range->inheritable)
-                {
-                  /* If CHANGE is a proper subset of RANGE, it absorbs RANGE
-                      with no adjustment otherwise only the intersection is
-                      absorbed and CHANGE is truncated. */
-                  if (range->end >= change->end)
-                    continue;
-                  else
-                    {
-                      change->start = range->end;
-                      j--;
-                      continue;
-                    }
-                }
-              else
-                {
-                  /* RANGE is non-inheritable and CHANGE is inheritable. */
-                  if (range->start < change->start)
-                    {
-                      /* CHANGE absorbs intersection with RANGE and RANGE
-                         is truncated. */
-                      svn_merge_range_t *range_copy =
-                        svn_merge_range_dup(range, result_pool);
-                      range_copy->end = change->start;
-                      range->start = change->start;
-                      svn_sort__array_insert(rangelist, &range_copy, i++);
-                      j--;
-                      continue;
-                    }
-                  else
-                    {
-                      /* CHANGE and RANGE share the same start rev, but
-                         RANGE is considered older because its end rev
-                         is older. */
-                      range->inheritable = TRUE;
-                      change->start = range->end;
-                      j--;
-                      continue;
-                    }
-                }
-            }
-        }
-      else /* res > 0, CHANGE is older than RANGE */
-        {
-          if (change->end == range->start)
-            {
-              /* RANGE and CHANGE adjoin */
-              if (range->inheritable == change->inheritable)
-                {
-                  /* RANGE and CHANGE have the same inheritability so we
-                     can simply combine the two in place. */
-                  range->start = change->start;
-                  continue;
-                }
-              else
-                {
-                  /* RANGE and CHANGE have different inheritability so insert
-                     a copy of CHANGE into RANGELIST. */
-                  SVN_ERR_MALFUNCTION(); /* Already handled */
-                }
-            }
-          else
-            {
-              /* RANGE and CHANGE overlap. */
-              if (range->inheritable == change->inheritable)
-                {
-                  /* RANGE and CHANGE have the same inheritability so we
-                     can simply combine the two in place... */
-                  range->start = change->start;
-                  if (range->end < change->end)
-                    {
-                      /* ...but if RANGE is expanded ensure that we don't
-                         violate any rangelist invariants. */
-                      range->end = change->end;
-                      adjust_remaining_ranges(rangelist, &i, result_pool);
-                    }
-                  continue;
-                }
-              else if (range->inheritable)
-                {
-                  if (change->start < range->start)
-                    {
-                      /* RANGE is inheritable so absorbs any part of CHANGE
-                         it overlaps.  CHANGE is truncated and the remainder
-                         inserted into RANGELIST. */
-                      SVN_ERR_MALFUNCTION(); /* Already handled */
-                    }
-                  else
-                    {
-                      /* CHANGE and RANGE share the same start rev, but
-                         CHANGE is considered older because CHANGE->END is
-                         older than RANGE->END. */
-                      continue;
-                    }
-                }
-              else
-                {
-                  /* RANGE is non-inheritable and CHANGE is inheritable. */
-                  if (change->start < range->start)
-                    {
-                      if (change->end == range->end)
-                        {
-                          /* RANGE is a proper subset of CHANGE and share the
-                             same end revision, so set RANGE equal to CHANGE. 
*/
-                          range->start = change->start;
-                          range->inheritable = TRUE;
-                          continue;
-                        }
-                      else if (change->end > range->end)
-                        {
-                          /* RANGE is a proper subset of CHANGE and CHANGE has
-                             a younger end revision, so set RANGE equal to its
-                             intersection with CHANGE and truncate CHANGE. */
-                          range->start = change->start;
-                          range->inheritable = TRUE;
-                          change->start = range->end;
-                          j--;
-                          continue;
-                        }
-                      else
-                        {
-                          /* CHANGE and RANGE overlap. Set RANGE equal to its
-                             intersection with CHANGE and take the remainder
-                             of RANGE and insert it into RANGELIST. */
-                          svn_merge_range_t *range_copy =
-                            svn_merge_range_dup(range, result_pool);
-                          range_copy->start = change->end;
-                          range->start = change->start;
-                          range->end = change->end;
-                          range->inheritable = TRUE;
-                          svn_sort__array_insert(rangelist, &range_copy, ++i);
-                          continue;
-                        }
-                    }
-                  else
-                    {
-                      /* CHANGE and RANGE share the same start rev, but
-                         CHANGE is considered older because its end rev
-                         is older.
-
-                         Insert the intersection of RANGE and CHANGE into
-                         RANGELIST and then set RANGE to the non-intersecting
-                         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(rangelist, &range_copy, i++);
-                      continue;
-                    }
-                }
-            }
-        }
-      SVN_ERR_MALFUNCTION(); /* Unreachable */
-    }
+  /* Move the original rangelist aside. A shallow copy suffices,
+   * as rangelist_merge() won't modify its inputs. */
+  rangelist_orig = apr_array_copy(scratch_pool, rangelist);
+  apr_array_clear(rangelist);
+  err = svn_error_trace(rangelist_merge(rangelist, rangelist_orig, chg,
+                                        result_pool, scratch_pool));
 
 #ifdef SVN_DEBUG
-  SVN_ERR_ASSERT(svn_rangelist__is_canonical(rangelist));
+  if (err)
+    {
+      err = svn_error_createf(SVN_ERR_ASSERTION_FAIL, err,
+              "svn_rangelist_merge2( %s / %s ): internal error",
+              rangelist_to_string_debug(rangelist_orig, scratch_pool),
+              rangelist_to_string_debug(chg, scratch_pool));
+    }
+  else if (! svn_rangelist__is_canonical(rangelist)
+           && svn_rangelist__is_canonical(rangelist_orig)
+           && svn_rangelist__is_canonical(chg))
+    {
+      err = svn_error_createf(SVN_ERR_ASSERTION_FAIL, NULL,
+              "svn_rangelist_merge2( %s / %s ): canonical inputs, "
+              "non-canonical result ( %s )",
+              rangelist_to_string_debug(rangelist_orig, scratch_pool),
+              rangelist_to_string_debug(chg, scratch_pool),
+              rangelist_to_string_debug(rangelist, scratch_pool));
+    }
 #endif
 
-  return SVN_NO_ERROR;
+  return err;
 }
 
-/* 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,
+/* Set *RESULT to TRUE iff the forward revision ranges FIRST and SECOND overlap
+ * and (if CONSIDER_INHERITANCE is TRUE) have the same inheritability. */
+static svn_error_t *
+range_intersect(svn_boolean_t *result,
+                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));
+  SVN_ERR_ASSERT(IS_VALID_FORWARD_RANGE(first));
+  SVN_ERR_ASSERT(IS_VALID_FORWARD_RANGE(second));
 
-  return (first->start + 1 <= second->end)
-    && (second->start + 1 <= first->end)
-    && (!consider_inheritance
-        || (!(first->inheritable) == !(second->inheritable)));
+  *result = (first->start + 1 <= second->end)
+            && (second->start + 1 <= first->end)
+            && (!consider_inheritance
+                || (!(first->inheritable) == !(second->inheritable)));
+  return SVN_NO_ERROR;
 }
 
-/* Return TRUE iff the forward revision range FIRST wholly contains the
+/* Set *RESULT to 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,
+static svn_error_t *
+range_contains(svn_boolean_t *result,
+               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));
+  SVN_ERR_ASSERT(IS_VALID_FORWARD_RANGE(first));
+  SVN_ERR_ASSERT(IS_VALID_FORWARD_RANGE(second));
 
-  return (first->start <= second->start) && (second->end <= first->end)
-    && (!consider_inheritance
-        || (!(first->inheritable) == !(second->inheritable)));
+  *result = (first->start <= second->start) && (second->end <= first->end)
+            && (!consider_inheritance
+                || (!(first->inheritable) == !(second->inheritable)));
+  return SVN_NO_ERROR;
 }
 
 /* Swap start and end fields of RANGE. */
@@ -1390,6 +1277,7 @@ rangelist_intersect_or_remove(svn_rangel
   while (i1 < rangelist1->nelts && i2 < rangelist2->nelts)
     {
       svn_merge_range_t *elt1, *elt2;
+      svn_boolean_t elt1_contains_elt2, elt1_intersects_elt2;
 
       elt1 = APR_ARRAY_IDX(rangelist1, i1, svn_merge_range_t *);
 
@@ -1405,6 +1293,10 @@ rangelist_intersect_or_remove(svn_rangel
 
       elt2 = &working_elt2;
 
+      SVN_ERR(range_contains(&elt1_contains_elt2,
+                             elt1, elt2, consider_inheritance));
+      SVN_ERR(range_intersect(&elt1_intersects_elt2,
+                              elt1, elt2, consider_inheritance));
       /* If the rangelist2 range is contained completely in the
          rangelist1, we increment the rangelist2.
          If the ranges intersect, and match exactly, we increment both
@@ -1413,7 +1305,7 @@ rangelist_intersect_or_remove(svn_rangel
          the removal of rangelist1 from rangelist2, and possibly change
          the rangelist2 to the remaining portion of the right part of
          the removal, to test against. */
-      if (range_contains(elt1, elt2, consider_inheritance))
+      if (elt1_contains_elt2)
         {
           if (!do_remove)
             {
@@ -1434,7 +1326,7 @@ rangelist_intersect_or_remove(svn_rangel
           if (elt2->start == elt1->start && elt2->end == elt1->end)
             i1++;
         }
-      else if (range_intersect(elt1, elt2, consider_inheritance))
+      else if (elt1_intersects_elt2)
         {
           if (elt2->start < elt1->start)
             {
@@ -1977,18 +1869,21 @@ svn_rangelist_to_string(svn_string_t **o
     {
       int i;
       svn_merge_range_t *range;
+      char *s;
 
       /* Handle the elements that need commas at the end.  */
       for (i = 0; i < rangelist->nelts - 1; i++)
         {
           range = APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *);
-          svn_stringbuf_appendcstr(buf, range_to_string(range, pool));
+          SVN_ERR(range_to_string(&s, range, pool));
+          svn_stringbuf_appendcstr(buf, s);
           svn_stringbuf_appendcstr(buf, ",");
         }
 
       /* Now handle the last element, which needs no comma.  */
       range = APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *);
-      svn_stringbuf_appendcstr(buf, range_to_string(range, pool));
+      SVN_ERR(range_to_string(&s, range, pool));
+      svn_stringbuf_appendcstr(buf, s);
     }
 
   *output = svn_stringbuf__morph_into_string(buf);

Modified: subversion/branches/addremove/subversion/libsvn_subr/object_pool.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_subr/object_pool.c?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/libsvn_subr/object_pool.c 
(original)
+++ subversion/branches/addremove/subversion/libsvn_subr/object_pool.c Sat May 
23 14:16:56 2020
@@ -172,9 +172,11 @@ add_object_ref(object_ref_t *object_ref,
   if (svn_atomic_inc(&object_ref->ref_count) == 0)
     svn_atomic_dec(&object_ref->object_pool->unused_count);
 
-  /* make sure the reference gets released automatically */
-  apr_pool_cleanup_register(pool, object_ref, object_ref_cleanup,
-                            apr_pool_cleanup_null);
+  /* Make sure the reference gets released automatically.
+     Since POOL might be a parent pool of OBJECT_REF->OBJECT_POOL,
+     to the reference counting update before destroying any of the
+     pool hierarchy. */
+  apr_pool_pre_cleanup_register(pool, object_ref, object_ref_cleanup);
 }
 
 /* Actual implementation of svn_object_pool__lookup.
@@ -319,7 +321,7 @@ svn_object_pool__insert(void **object,
 {
   *object = NULL;
   SVN_MUTEX__WITH_LOCK(object_pool->mutex,
-                       insert(object, object_pool, key, item, 
+                       insert(object, object_pool, key, item,
                               item_pool, result_pool));
   return SVN_NO_ERROR;
 }

Modified: subversion/branches/addremove/subversion/libsvn_subr/opt.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_subr/opt.c?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/libsvn_subr/opt.c (original)
+++ subversion/branches/addremove/subversion/libsvn_subr/opt.c Sat May 23 
14:16:56 2020
@@ -55,8 +55,8 @@
 
 /*** Code. ***/
 
-const svn_opt_subcommand_desc2_t *
-svn_opt_get_canonical_subcommand2(const svn_opt_subcommand_desc2_t *table,
+const svn_opt_subcommand_desc3_t *
+svn_opt_get_canonical_subcommand3(const svn_opt_subcommand_desc3_t *table,
                                   const char *cmd_name)
 {
   int i = 0;
@@ -80,9 +80,9 @@ svn_opt_get_canonical_subcommand2(const
 }
 
 const apr_getopt_option_t *
-svn_opt_get_option_from_code2(int code,
+svn_opt_get_option_from_code3(int code,
                               const apr_getopt_option_t *option_table,
-                              const svn_opt_subcommand_desc2_t *command,
+                              const svn_opt_subcommand_desc3_t *command,
                               apr_pool_t *pool)
 {
   apr_size_t i;
@@ -111,34 +111,19 @@ svn_opt_get_option_from_code2(int code,
   return NULL;
 }
 
-
-const apr_getopt_option_t *
-svn_opt_get_option_from_code(int code,
-                             const apr_getopt_option_t *option_table)
-{
-  apr_size_t i;
-
-  for (i = 0; option_table[i].optch; i++)
-    if (option_table[i].optch == code)
-      return &(option_table[i]);
-
-  return NULL;
-}
-
-
-/* Like svn_opt_get_option_from_code2(), but also, if CODE appears a second
+/* Like svn_opt_get_option_from_code3(), but also, if CODE appears a second
  * time in OPTION_TABLE with a different name, then set *LONG_ALIAS to that
  * second name, else set it to NULL. */
 static const apr_getopt_option_t *
-get_option_from_code(const char **long_alias,
-                     int code,
-                     const apr_getopt_option_t *option_table,
-                     const svn_opt_subcommand_desc2_t *command,
-                     apr_pool_t *pool)
+get_option_from_code3(const char **long_alias,
+                      int code,
+                      const apr_getopt_option_t *option_table,
+                      const svn_opt_subcommand_desc3_t *command,
+                      apr_pool_t *pool)
 {
   const apr_getopt_option_t *i;
   const apr_getopt_option_t *opt
-    = svn_opt_get_option_from_code2(code, option_table, command, pool);
+    = svn_opt_get_option_from_code3(code, option_table, command, pool);
 
   /* Find a long alias in the table, if there is one. */
   *long_alias = NULL;
@@ -205,7 +190,7 @@ svn_opt_format_option(const char **strin
 
 
 svn_boolean_t
-svn_opt_subcommand_takes_option3(const svn_opt_subcommand_desc2_t *command,
+svn_opt_subcommand_takes_option4(const svn_opt_subcommand_desc3_t *command,
                                  int option_code,
                                  const int *global_options)
 {
@@ -223,38 +208,19 @@ svn_opt_subcommand_takes_option3(const s
   return FALSE;
 }
 
-svn_boolean_t
-svn_opt_subcommand_takes_option2(const svn_opt_subcommand_desc2_t *command,
-                                 int option_code)
-{
-  return svn_opt_subcommand_takes_option3(command,
-                                          option_code,
-                                          NULL);
-}
-
-
-svn_boolean_t
-svn_opt_subcommand_takes_option(const svn_opt_subcommand_desc_t *command,
-                                int option_code)
-{
-  apr_size_t i;
-
-  for (i = 0; i < SVN_OPT_MAX_OPTIONS; i++)
-    if (command->valid_options[i] == option_code)
-      return TRUE;
-
-  return FALSE;
-}
-
 
 /* Print the canonical command name for CMD, and all its aliases, to
    STREAM.  If HELP is set, print CMD's help string too, in which case
-   obtain option usage from OPTIONS_TABLE. */
+   obtain option usage from OPTIONS_TABLE.
+
+   Include global and experimental options iff VERBOSE is true.
+ */
 static svn_error_t *
-print_command_info2(const svn_opt_subcommand_desc2_t *cmd,
+print_command_info3(const svn_opt_subcommand_desc3_t *cmd,
                     const apr_getopt_option_t *options_table,
                     const int *global_options,
                     svn_boolean_t help,
+                    svn_boolean_t verbose,
                     apr_pool_t *pool,
                     FILE *stream)
 {
@@ -289,8 +255,14 @@ print_command_info2(const svn_opt_subcom
       const apr_getopt_option_t *option;
       const char *long_alias;
       svn_boolean_t have_options = FALSE;
+      svn_boolean_t have_experimental = FALSE;
 
-      SVN_ERR(svn_cmdline_fprintf(stream, pool, ": %s", _(cmd->help)));
+      SVN_ERR(svn_cmdline_fprintf(stream, pool, ": "));
+
+      for (i = 0; i < SVN_OPT_MAX_PARAGRAPHS && cmd->help[i]; i++)
+        {
+          SVN_ERR(svn_cmdline_fprintf(stream, pool, "%s", _(cmd->help[i])));
+        }
 
       /* Loop over all valid option codes attached to the subcommand */
       for (i = 0; i < SVN_OPT_MAX_OPTIONS; i++)
@@ -305,13 +277,24 @@ print_command_info2(const svn_opt_subcom
                 }
 
               /* convert each option code into an option */
-              option = get_option_from_code(&long_alias, cmd->valid_options[i],
-                                            options_table, cmd, pool);
+              option = get_option_from_code3(&long_alias, 
cmd->valid_options[i],
+                                             options_table, cmd, pool);
 
               /* print the option's docstring */
               if (option && option->description)
                 {
                   const char *optstr;
+
+                  if (option->name && strncmp(option->name, "x-", 2) == 0)
+                    {
+                      if (verbose && !have_experimental)
+                        SVN_ERR(svn_cmdline_fputs(_("\nExperimental 
options:\n"),
+                                                  stream, pool));
+                      have_experimental = TRUE;
+                      if (!verbose)
+                        continue;
+                    }
+
                   format_option(&optstr, option, long_alias, TRUE, pool);
                   SVN_ERR(svn_cmdline_fprintf(stream, pool, "  %s\n",
                                               optstr));
@@ -319,7 +302,7 @@ print_command_info2(const svn_opt_subcom
             }
         }
       /* And global options too */
-      if (global_options && *global_options)
+      if (verbose && global_options && *global_options)
         {
           SVN_ERR(svn_cmdline_fputs(_("\nGlobal options:\n"),
                                     stream, pool));
@@ -329,8 +312,8 @@ print_command_info2(const svn_opt_subcom
             {
 
               /* convert each option code into an option */
-              option = get_option_from_code(&long_alias, global_options[i],
-                                            options_table, cmd, pool);
+              option = get_option_from_code3(&long_alias, global_options[i],
+                                             options_table, cmd, pool);
 
               /* print the option's docstring */
               if (option && option->description)
@@ -343,6 +326,9 @@ print_command_info2(const svn_opt_subcom
             }
         }
 
+      if (!verbose)
+        SVN_ERR(svn_cmdline_fputs(_("\n(Use '-v' to show global and 
experimental options.)\n"),
+                                  stream, pool));
       if (have_options)
         SVN_ERR(svn_cmdline_fprintf(stream, pool, "\n"));
     }
@@ -350,30 +336,44 @@ print_command_info2(const svn_opt_subcom
   return SVN_NO_ERROR;
 }
 
-/* The body for svn_opt_print_generic_help2() function with standard error
+/* The body for svn_opt_print_generic_help3() function with standard error
  * handling semantic. Handling of errors implemented at caller side. */
 static svn_error_t *
-print_generic_help_body(const char *header,
-                        const svn_opt_subcommand_desc2_t *cmd_table,
-                        const apr_getopt_option_t *opt_table,
-                        const char *footer,
-                        apr_pool_t *pool, FILE *stream)
+print_generic_help_body3(const char *header,
+                         const svn_opt_subcommand_desc3_t *cmd_table,
+                         const apr_getopt_option_t *opt_table,
+                         const char *footer,
+                         svn_boolean_t with_experimental,
+                         apr_pool_t *pool, FILE *stream)
 {
-  int i = 0;
+  svn_boolean_t have_experimental = FALSE;
+  int i;
 
   if (header)
     SVN_ERR(svn_cmdline_fputs(header, stream, pool));
 
-  while (cmd_table[i].name)
+  for (i = 0; cmd_table[i].name; i++)
     {
+      if (strncmp(cmd_table[i].name, "x-", 2) == 0)
+        {
+          if (with_experimental && !have_experimental)
+            SVN_ERR(svn_cmdline_fputs(_("\nExperimental subcommands:\n"),
+                                      stream, pool));
+          have_experimental = TRUE;
+          if (!with_experimental)
+            continue;
+        }
       SVN_ERR(svn_cmdline_fputs("   ", stream, pool));
-      SVN_ERR(print_command_info2(cmd_table + i, opt_table,
-                                  NULL, FALSE,
+      SVN_ERR(print_command_info3(cmd_table + i, opt_table,
+                                  NULL, FALSE, FALSE,
                                   pool, stream));
       SVN_ERR(svn_cmdline_fputs("\n", stream, pool));
-      i++;
     }
 
+  if (have_experimental && !with_experimental)
+    SVN_ERR(svn_cmdline_fputs(_("\n(Use '-v' to show experimental 
subcommands.)\n"),
+                              stream, pool));
+
   SVN_ERR(svn_cmdline_fputs("\n", stream, pool));
 
   if (footer)
@@ -382,17 +382,19 @@ print_generic_help_body(const char *head
   return SVN_NO_ERROR;
 }
 
-void
-svn_opt_print_generic_help2(const char *header,
-                            const svn_opt_subcommand_desc2_t *cmd_table,
-                            const apr_getopt_option_t *opt_table,
-                            const char *footer,
-                            apr_pool_t *pool, FILE *stream)
+static void
+print_generic_help(const char *header,
+                   const svn_opt_subcommand_desc3_t *cmd_table,
+                   const apr_getopt_option_t *opt_table,
+                   const char *footer,
+                   svn_boolean_t with_experimental,
+                   apr_pool_t *pool, FILE *stream)
 {
   svn_error_t *err;
 
-  err = print_generic_help_body(header, cmd_table, opt_table, footer, pool,
-                                stream);
+  err = print_generic_help_body3(header, cmd_table, opt_table, footer,
+                                 with_experimental,
+                                 pool, stream);
 
   /* Issue #3014:
    * Don't print anything on broken pipes. The pipe was likely
@@ -406,21 +408,37 @@ svn_opt_print_generic_help2(const char *
   svn_error_clear(err);
 }
 
-
 void
-svn_opt_subcommand_help3(const char *subcommand,
-                         const svn_opt_subcommand_desc2_t *table,
-                         const apr_getopt_option_t *options_table,
-                         const int *global_options,
-                         apr_pool_t *pool)
+svn_opt_print_generic_help3(const char *header,
+                            const svn_opt_subcommand_desc3_t *cmd_table,
+                            const apr_getopt_option_t *opt_table,
+                            const char *footer,
+                            apr_pool_t *pool, FILE *stream)
 {
-  const svn_opt_subcommand_desc2_t *cmd =
-    svn_opt_get_canonical_subcommand2(table, subcommand);
+  print_generic_help(header, cmd_table, opt_table, footer,
+                     TRUE, pool, stream);
+}
+
+
+/* The body of svn_opt_subcommand_help4(), which see.
+ *
+ * VERBOSE means show also the subcommand's global and experimental options.
+ */
+static void
+subcommand_help(const char *subcommand,
+                const svn_opt_subcommand_desc3_t *table,
+                const apr_getopt_option_t *options_table,
+                const int *global_options,
+                svn_boolean_t verbose,
+                apr_pool_t *pool)
+{
+  const svn_opt_subcommand_desc3_t *cmd =
+    svn_opt_get_canonical_subcommand3(table, subcommand);
   svn_error_t *err;
 
   if (cmd)
-    err = print_command_info2(cmd, options_table, global_options,
-                              TRUE, pool, stdout);
+    err = print_command_info3(cmd, options_table, global_options,
+                              TRUE, verbose, pool, stdout);
   else
     err = svn_cmdline_fprintf(stderr, pool,
                               _("\"%s\": unknown command.\n\n"), subcommand);
@@ -433,6 +451,17 @@ svn_opt_subcommand_help3(const char *sub
   }
 }
 
+void
+svn_opt_subcommand_help4(const char *subcommand,
+                         const svn_opt_subcommand_desc3_t *table,
+                         const apr_getopt_option_t *options_table,
+                         const int *global_options,
+                         apr_pool_t *pool)
+{
+  subcommand_help(subcommand, table, options_table, global_options,
+                  TRUE, pool);
+}
+
 
 
 /*** Parsing revision and date options. ***/
@@ -1194,14 +1223,14 @@ svn_opt__print_version_info(const char *
 }
 
 svn_error_t *
-svn_opt_print_help4(apr_getopt_t *os,
+svn_opt_print_help5(apr_getopt_t *os,
                     const char *pgm_name,
                     svn_boolean_t print_version,
                     svn_boolean_t quiet,
                     svn_boolean_t verbose,
                     const char *version_footer,
                     const char *header,
-                    const svn_opt_subcommand_desc2_t *cmd_table,
+                    const svn_opt_subcommand_desc3_t *cmd_table,
                     const apr_getopt_option_t *option_table,
                     const int *global_options,
                     const char *footer,
@@ -1218,9 +1247,9 @@ svn_opt_print_help4(apr_getopt_t *os,
 
       for (i = 0; i < targets->nelts; i++)
         {
-          svn_opt_subcommand_help3(APR_ARRAY_IDX(targets, i, const char *),
-                                   cmd_table, option_table,
-                                   global_options, pool);
+          subcommand_help(APR_ARRAY_IDX(targets, i, const char *),
+                          cmd_table, option_table, global_options,
+                          verbose, pool);
         }
     }
   else if (print_version)   /* just --version */
@@ -1230,12 +1259,9 @@ svn_opt_print_help4(apr_getopt_t *os,
                                           quiet, verbose, pool));
     }
   else if (os && !targets->nelts)            /* `-h', `--help', or `help' */
-    svn_opt_print_generic_help2(header,
-                                cmd_table,
-                                option_table,
-                                footer,
-                                pool,
-                                stdout);
+    print_generic_help(header, cmd_table, option_table, footer,
+                       verbose,
+                       pool, stdout);
   else                                       /* unknown option or cmd */
     SVN_ERR(svn_cmdline_fprintf(stderr, pool,
                                 _("Type '%s help' for usage.\n"), pgm_name));

Modified: subversion/branches/addremove/subversion/libsvn_subr/path.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_subr/path.c?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/libsvn_subr/path.c (original)
+++ subversion/branches/addremove/subversion/libsvn_subr/path.c Sat May 23 
14:16:56 2020
@@ -590,7 +590,7 @@ svn_path_is_ancestor(const char *path1,
 {
   apr_size_t path1_len = strlen(path1);
 
-  /* If path1 is empty and path2 is not absoulte, then path1 is an ancestor. */
+  /* If path1 is empty and path2 is not absolute, then path1 is an ancestor. */
   if (SVN_PATH_IS_EMPTY(path1))
     return *path2 != '/';
 

Modified: subversion/branches/addremove/subversion/libsvn_subr/pool.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_subr/pool.c?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/libsvn_subr/pool.c (original)
+++ subversion/branches/addremove/subversion/libsvn_subr/pool.c Sat May 23 
14:16:56 2020
@@ -133,7 +133,7 @@ svn_pool_create_allocator(svn_boolean_t
 #endif
 
   /* By default, allocators are *not* thread-safe. We must provide a mutex
-   * if we want thread-safety for that mutex. */
+   * if we want thread-safety for that pool. */
 
 #if APR_HAS_THREADS
   if (thread_safe)
@@ -151,16 +151,6 @@ svn_pool_create_allocator(svn_boolean_t
 }
 
 
-/*
- * apr_pool_create_core_ex was introduced in APR 1.3.0, then
- * deprecated and renamed to apr_pool_create_unmanaged_ex in 1.3.3.
- * Since our minimum requirement is APR 1.3.0, one or the other of
- * these functions will always be available.
- */
-#if !APR_VERSION_AT_LEAST(1,3,3)
-#define apr_pool_create_unmanaged_ex apr_pool_create_core_ex
-#endif
-
 /* Private function that creates an unmanaged pool. */
 apr_pool_t *
 svn_pool__create_unmanaged(svn_boolean_t thread_safe)

Modified: subversion/branches/addremove/subversion/libsvn_subr/prompt.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_subr/prompt.c?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/libsvn_subr/prompt.c (original)
+++ subversion/branches/addremove/subversion/libsvn_subr/prompt.c Sat May 23 
14:16:56 2020
@@ -262,7 +262,7 @@ terminal_puts(const char *string, termin
 
 /* These codes can be returned from terminal_getc instead of a character. */
 #define TERMINAL_NONE  0x80000               /* no character read, retry */
-#define TERMINAL_DEL   (TERMINAL_NONE + 1)   /* the input was a deleteion */
+#define TERMINAL_DEL   (TERMINAL_NONE + 1)   /* the input was a deletion */
 #define TERMINAL_EOL   (TERMINAL_NONE + 2)   /* end of input/end of line */
 #define TERMINAL_EOF   (TERMINAL_NONE + 3)   /* end of file during input */
 

Modified: subversion/branches/addremove/subversion/libsvn_subr/sorts.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_subr/sorts.c?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/libsvn_subr/sorts.c (original)
+++ subversion/branches/addremove/subversion/libsvn_subr/sorts.c Sat May 23 
14:16:56 2020
@@ -34,6 +34,8 @@
 #include "svn_error.h"
 #include "private/svn_sorts_private.h"
 
+#include "svn_private_config.h"
+
 
 
 /*** svn_sort__hash() ***/
@@ -299,15 +301,20 @@ svn_sort__array_lookup(const apr_array_h
   return compare_func(result, key) ? NULL : result;
 }
 
-void
-svn_sort__array_insert(apr_array_header_t *array,
-                       const void *new_element,
-                       int insert_index)
+svn_error_t *
+svn_sort__array_insert2(apr_array_header_t *array,
+                        const void *new_element,
+                        int insert_index)
 {
   int elements_to_move;
   char *new_position;
 
-  assert(0 <= insert_index && insert_index <= array->nelts);
+  if (insert_index < 0 || insert_index > array->nelts)
+    return svn_error_createf(SVN_ERR_INCORRECT_PARAMS, NULL,
+                             _("svn_sort__array_insert2: Attempted insert "
+                               "at index %d in array length %d"),
+                             insert_index, array->nelts);
+
   elements_to_move = array->nelts - insert_index;  /* before bumping nelts */
 
   /* Grow the array, allocating a new space at the end. Note: this can
@@ -322,31 +329,35 @@ svn_sort__array_insert(apr_array_header_
 
   /* Copy in the new element */
   memcpy(new_position, new_element, array->elt_size);
+  return SVN_NO_ERROR;
 }
 
-void
-svn_sort__array_delete(apr_array_header_t *arr,
-                       int delete_index,
-                       int elements_to_delete)
-{
-  /* Do we have a valid index and are there enough elements? */
-  if (delete_index >= 0
-      && delete_index < arr->nelts
-      && elements_to_delete > 0
-      && (arr->nelts - delete_index) >= elements_to_delete)
-    {
-      /* If we are not deleting a block of elements that extends to the end
-         of the array, then we need to move the remaining elements to keep
-         the array contiguous. */
-      if ((elements_to_delete + delete_index) < arr->nelts)
-        memmove(
-          arr->elts + arr->elt_size * delete_index,
-          arr->elts + (arr->elt_size * (delete_index + elements_to_delete)),
-          arr->elt_size * (arr->nelts - elements_to_delete - delete_index));
-
-      /* Delete the last ELEMENTS_TO_DELETE elements. */
-      arr->nelts -= elements_to_delete;
-    }
+svn_error_t *
+svn_sort__array_delete2(apr_array_header_t *arr,
+                        int delete_index,
+                        int elements_to_delete)
+{
+  if (!(delete_index >= 0
+        && delete_index < arr->nelts
+        && elements_to_delete > 0
+        && (arr->nelts - delete_index) >= elements_to_delete))
+    return svn_error_createf(SVN_ERR_INCORRECT_PARAMS, NULL,
+                             _("svn_sort__array_delete2: Attempted delete "
+                               "at index %d, %d elements, in array length %d"),
+                             delete_index, elements_to_delete, arr->nelts);
+
+  /* If we are deleting a block of elements that does not extend to the end
+     of the array, then we need to move the remaining elements to keep
+     the array contiguous. */
+  if ((elements_to_delete + delete_index) < arr->nelts)
+    memmove(
+      arr->elts + arr->elt_size * delete_index,
+      arr->elts + (arr->elt_size * (delete_index + elements_to_delete)),
+      arr->elt_size * (arr->nelts - elements_to_delete - delete_index));
+
+  /* Delete the last ELEMENTS_TO_DELETE elements. */
+  arr->nelts -= elements_to_delete;
+  return SVN_NO_ERROR;
 }
 
 void

Modified: subversion/branches/addremove/subversion/libsvn_subr/sqlite.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_subr/sqlite.c?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/libsvn_subr/sqlite.c (original)
+++ subversion/branches/addremove/subversion/libsvn_subr/sqlite.c Sat May 23 
14:16:56 2020
@@ -65,8 +65,8 @@ extern int (*const svn_sqlite3__api_conf
 #  include <sqlite3.h>
 #endif
 
-#if !SQLITE_VERSION_AT_LEAST(3,7,12)
-#error SQLite is too old -- version 3.7.12 is the minimum required version
+#if !SQLITE_VERSION_AT_LEAST(3,8,2)
+#error SQLite is too old -- version 3.8.2 is the minimum required version
 #endif
 
 #ifndef SQLITE_DETERMINISTIC

Modified: subversion/branches/addremove/subversion/libsvn_subr/sqlite3wrapper.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_subr/sqlite3wrapper.c?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/libsvn_subr/sqlite3wrapper.c 
(original)
+++ subversion/branches/addremove/subversion/libsvn_subr/sqlite3wrapper.c Sat 
May 23 14:16:56 2020
@@ -25,6 +25,8 @@
 /* Include sqlite3 inline, making all symbols private. */
 #ifdef SVN_SQLITE_INLINE
 #  define SQLITE_OMIT_DEPRECATED 1
+#  define SQLITE_DEFAULT_MEMSTATUS 0
+#  define SQLITE_OMIT_WAL 1
 #  define SQLITE_API static
 #  if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2)
 #    pragma GCC diagnostic ignored "-Wunreachable-code"
@@ -41,6 +43,12 @@
 #    endif
 #  endif
 #  ifdef __APPLE__
+     /* SQLite uses OSAtomicCompareAndSwapPtrBarrier from libkern/OSAtomic.h,
+        which has been deprecated since macOS 10.12. This will silence the
+        warning. */
+#    if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2)
+#      pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#    endif
 #    include <Availability.h>
 #    if __MAC_OS_X_VERSION_MIN_REQUIRED < 1060
        /* <libkern/OSAtomic.h> is included on OS X by sqlite3.c, and

Modified: 
subversion/branches/addremove/subversion/libsvn_subr/ssl_client_cert_pw_providers.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_subr/ssl_client_cert_pw_providers.c?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- 
subversion/branches/addremove/subversion/libsvn_subr/ssl_client_cert_pw_providers.c
 (original)
+++ 
subversion/branches/addremove/subversion/libsvn_subr/ssl_client_cert_pw_providers.c
 Sat May 23 14:16:56 2020
@@ -36,7 +36,7 @@
 #include "svn_private_config.h"
 
 /*-----------------------------------------------------------------------*/
-/* File provider                                                         */
+/* File password provider                                                */
 /*-----------------------------------------------------------------------*/
 
 /* Baton type for the ssl client cert passphrase provider. */
@@ -51,6 +51,13 @@ typedef struct ssl_client_cert_pw_file_p
   apr_hash_t *plaintext_answers;
 } ssl_client_cert_pw_file_provider_baton_t;
 
+/* The client cert password provider only deals with a password and
+   realm (the client cert filename), there is no username.  The gnome
+   keyring backend based on libsecret requires a non-NULL username so
+   we have to invent one.  An empty string is acceptable and doesn't
+   change the value stored by the kwallet backend. */
+#define DUMMY_USERNAME ""
+
 /* This implements the svn_auth__password_get_t interface.
    Set **PASSPHRASE to the plaintext passphrase retrieved from CREDS;
    ignore other parameters. */
@@ -132,7 +139,8 @@ svn_auth__ssl_client_cert_pw_cache_get(v
           svn_boolean_t done;
 
           SVN_ERR(passphrase_get(&done, &password, creds_hash, realmstring,
-                                 NULL, parameters, non_interactive, pool));
+                                 DUMMY_USERNAME, parameters, non_interactive,
+                                 pool));
           if (!done)
             password = NULL;
         }
@@ -293,7 +301,7 @@ svn_auth__ssl_client_cert_pw_cache_set(s
       if (may_save_passphrase)
         {
           SVN_ERR(passphrase_set(saved, creds_hash, realmstring,
-                                 NULL, creds->password, parameters,
+                                 DUMMY_USERNAME, creds->password, parameters,
                                  non_interactive, pool));
 
           if (*saved && passtype)

Modified: subversion/branches/addremove/subversion/libsvn_subr/stream.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_subr/stream.c?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/libsvn_subr/stream.c (original)
+++ subversion/branches/addremove/subversion/libsvn_subr/stream.c Sat May 23 
14:16:56 2020
@@ -922,7 +922,7 @@ readline_apr_lf(apr_file_t *file,
       }
 
     /* Otherwise, prepare to read the next chunk. */
-    svn_stringbuf_ensure(buf, buf->blocksize + SVN__LINE_CHUNK_SIZE);
+    svn_stringbuf_ensure(buf, buf->len + SVN__LINE_CHUNK_SIZE);
   }
 }
 
@@ -982,7 +982,7 @@ readline_apr_generic(apr_file_t *file,
         }
 
       /* Prepare to read the next chunk. */
-      svn_stringbuf_ensure(buf, buf->blocksize + SVN__LINE_CHUNK_SIZE);
+      svn_stringbuf_ensure(buf, buf->len + SVN__LINE_CHUNK_SIZE);
     }
 }
 
@@ -1468,10 +1468,10 @@ seek_handler_checksum(void *baton, const
   else
     {
       if (btn->read_ctx)
-        svn_checksum_ctx_reset(btn->read_ctx);
+        SVN_ERR(svn_checksum_ctx_reset(btn->read_ctx));
 
       if (btn->write_ctx)
-        svn_checksum_ctx_reset(btn->write_ctx);
+        SVN_ERR(svn_checksum_ctx_reset(btn->write_ctx));
 
       SVN_ERR(svn_stream_reset(btn->proxy));
     }

Modified: subversion/branches/addremove/subversion/libsvn_subr/string.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_subr/string.c?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/libsvn_subr/string.c (original)
+++ subversion/branches/addremove/subversion/libsvn_subr/string.c Sat May 23 
14:16:56 2020
@@ -65,7 +65,7 @@ membuf_create(void **data, apr_size_t *s
  * this function does nothing.
  *
  * If *SIZE is 0, the allocated buffer size will be MINIMUM_SIZE
- * rounded up to the nearest APR alignment boundary. Otherwse, *SIZE
+ * rounded up to the nearest APR alignment boundary. Otherwise, *SIZE
  * will be multiplied by a power of two such that the result is
  * greater or equal to MINIMUM_SIZE. The pointer to the new buffer
  * will be returned in *DATA, and its size in *SIZE.

Modified: subversion/branches/addremove/subversion/libsvn_subr/sysinfo.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_subr/sysinfo.c?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/libsvn_subr/sysinfo.c (original)
+++ subversion/branches/addremove/subversion/libsvn_subr/sysinfo.c Sat May 23 
14:16:56 2020
@@ -1,3 +1,4 @@
+
 /*
  * sysinfo.c :  information about the running system
  *
@@ -51,10 +52,22 @@
 #include "sysinfo.h"
 #include "svn_private_config.h"
 
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
 #if HAVE_SYS_UTSNAME_H
 #include <sys/utsname.h>
 #endif
 
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#if HAVE_ELF_H
+#include <elf.h>
+#endif
+
 #ifdef SVN_HAVE_MACOS_PLIST
 #include <CoreFoundation/CoreFoundation.h>
 #include <AvailabilityMacros.h>
@@ -92,6 +105,7 @@ static const apr_array_header_t *macos_s
 
 #if __linux__
 static const char *linux_release_name(apr_pool_t *pool);
+static const apr_array_header_t *linux_shared_libs(apr_pool_t *pool);
 #endif
 
 const char *
@@ -127,7 +141,8 @@ const apr_array_header_t *
 svn_sysinfo__linked_libs(apr_pool_t *pool)
 {
   svn_version_ext_linked_lib_t *lib;
-  apr_array_header_t *array = apr_array_make(pool, 6, sizeof(*lib));
+  apr_array_header_t *array = apr_array_make(pool, 7, sizeof(*lib));
+  int lz4_version = svn_lz4__runtime_version();
 
   lib = &APR_ARRAY_PUSH(array, svn_version_ext_linked_lib_t);
   lib->name = "APR";
@@ -167,6 +182,15 @@ svn_sysinfo__linked_libs(apr_pool_t *poo
   lib->compiled_version = apr_pstrdup(pool, svn_zlib__compiled_version());
   lib->runtime_version = apr_pstrdup(pool, svn_zlib__runtime_version());
 
+  lib = &APR_ARRAY_PUSH(array, svn_version_ext_linked_lib_t);
+  lib->name = "LZ4";
+  lib->compiled_version = apr_pstrdup(pool, svn_lz4__compiled_version());
+
+  lib->runtime_version = apr_psprintf(pool, "%d.%d.%d",
+                                      lz4_version / 100 / 100,
+                                      (lz4_version / 100) % 100,
+                                      lz4_version % 100);
+
   return array;
 }
 
@@ -177,6 +201,8 @@ svn_sysinfo__loaded_libs(apr_pool_t *poo
   return win32_shared_libs(pool);
 #elif defined(SVN_HAVE_MACHO_ITERATE)
   return macos_shared_libs(pool);
+#elif __linux__
+  return linux_shared_libs(pool);
 #else
   return NULL;
 #endif
@@ -290,6 +316,31 @@ release_name_from_uname(apr_pool_t *pool
 
 
 #if __linux__
+/* Find the first whitespace character in a stringbuf.
+   Analogous to svn_stringbuf_first_non_whitespace. */
+static apr_size_t
+stringbuf_first_whitespace(const svn_stringbuf_t *str)
+{
+  apr_size_t i;
+  for (i = 0; i < str->len; ++i)
+    {
+      if (svn_ctype_isspace(str->data[i]))
+        return i;
+    }
+  return str->len;
+}
+
+/* Skip a whitespace-delimited field in a stringbuf. */
+static void
+stringbuf_skip_whitespace_field(svn_stringbuf_t *str)
+{
+  apr_size_t i;
+  i = stringbuf_first_whitespace(str);
+  svn_stringbuf_leftchop(str, i);
+  i = svn_stringbuf_first_non_whitespace(str);
+  svn_stringbuf_leftchop(str, i);
+}
+
 /* Split a stringbuf into a key/value pair.
    Return the key, leaving the stripped value in the stringbuf. */
 static const char *
@@ -625,6 +676,168 @@ linux_release_name(apr_pool_t *pool)
 
   return apr_psprintf(pool, "%s [%s]", release_name, uname_release);
 }
+
+#if HAVE_ELF_H
+/* Parse a hexadecimal number as a pointer value. */
+static const unsigned char *
+parse_pointer_value(const char *start, const char *limit, char **end)
+{
+  const unsigned char *ptr;
+  const apr_uint64_t val = (apr_uint64_t)apr_strtoi64(start, end, 16);
+
+  if (errno                     /* overflow */
+      || *end == start          /* no valid digits */
+      || *end >= limit)         /* representation too long */
+    return NULL;
+
+  ptr = (const unsigned char*)val;
+  if (val != (apr_uint64_t)ptr)  /* truncated value */
+    return NULL;
+
+  return ptr;
+}
+
+/* Read the ELF header at the mapping position to check if this is a shared
+   library. We only look at the ELF identification and the type. The format is
+   described here:
+       http://www.skyfree.org/linux/references/ELF_Format.pdf
+*/
+static svn_boolean_t
+check_elf_header(const unsigned char *map_start,
+                 const unsigned char *map_end)
+{
+  /* A union of all known ELF header types, for size checks. */
+  union max_elf_header_size_t
+  {
+    Elf32_Ehdr header_32;
+    Elf64_Ehdr header_64;
+  };
+
+  /* Check the size of the mapping and the ELF magic tag. */
+  if (map_end < map_start
+      || map_end - map_start < sizeof(union max_elf_header_size_t)
+      || memcmp(map_start, ELFMAG, SELFMAG))
+    {
+      return FALSE;
+    }
+
+  /* Check that this is an ELF shared library or executable file. This also
+     implicitly checks that the data encoding of the current process is the
+     same as in the loaded library. */
+  if (map_start[EI_CLASS] == ELFCLASS32)
+    {
+      const Elf32_Ehdr *hdr = (void*)map_start;
+      return (hdr->e_type == ET_DYN || hdr->e_type == ET_EXEC);
+    }
+  else if (map_start[EI_CLASS] == ELFCLASS64)
+    {
+      const Elf64_Ehdr *hdr = (void*)map_start;
+      return (hdr->e_type == ET_DYN || hdr->e_type == ET_EXEC);
+    }
+
+  return FALSE;
+}
+#endif  /* HAVE_ELF_H */
+
+static const apr_array_header_t *
+linux_shared_libs(apr_pool_t *pool)
+{
+  /* Read the list of loaded modules from /proc/[pid]/maps
+    The format is described here:
+        http://man7.org/linux/man-pages/man5/proc.5.html
+  */
+
+  const char *maps = apr_psprintf(pool, "/proc/%ld/maps", (long)getpid());
+  apr_array_header_t *result = NULL;
+  svn_boolean_t eof = FALSE;
+  svn_stream_t *stream;
+  svn_error_t *err;
+
+  err = svn_stream_open_readonly(&stream, maps, pool, pool);
+  if (err)
+    {
+      svn_error_clear(err);
+      return NULL;
+    }
+
+  /* Each line in /proc/[pid]/maps consists of whitespace-delimited fields. */
+  while (!eof)
+    {
+      svn_stringbuf_t *line;
+
+#if HAVE_ELF_H
+      const unsigned char *map_start;
+      const unsigned char *map_end;
+#endif
+
+      err = svn_stream_readline(stream, &line, "\n", &eof, pool);
+      if (err)
+        {
+          svn_error_clear(err);
+          return NULL;
+        }
+
+#if HAVE_ELF_H
+      /* Address: The mapped memory address range. */
+      {
+        const char *const limit = line->data + line->len;
+        char *end;
+
+        /* The start of the address range */
+        map_start = parse_pointer_value(line->data, limit, &end);
+        if (!map_start || *end != '-')
+          continue;
+
+        /* The end of the address range */
+        map_end = parse_pointer_value(end + 1, limit, &end);
+        if (!map_end || !svn_ctype_isspace(*end))
+          continue;
+      }
+#endif
+
+      stringbuf_skip_whitespace_field(line); /* skip address */
+
+      /* Permissions: The memory region must be readable and executable. */
+      if (line->len < 4 || line->data[0] != 'r' || line->data[2] != 'x')
+        continue;
+
+      stringbuf_skip_whitespace_field(line); /* skip perms */
+      stringbuf_skip_whitespace_field(line); /* skip offset */
+      stringbuf_skip_whitespace_field(line); /* skip device */
+
+      /* I-Node: If it is 0, there is no file associated with the region. */
+      if (line->len < 2
+          || (line->data[0] == '0' && svn_ctype_isspace(line->data[1])))
+        continue;
+
+      stringbuf_skip_whitespace_field(line); /* skip inode */
+
+      /* Consider only things that look like absolute paths.
+         Files that were removed since the process was created (due to an
+         upgrade, for example) are marked as '(deleted)'. */
+      if (line->data[0] == '/')
+        {
+          svn_version_ext_loaded_lib_t *lib;
+
+#if HAVE_ELF_H
+          if (!check_elf_header(map_start, map_end))
+            continue;
+#endif
+
+          /* We've done our best to find a mapped shared library. */
+          if (!result)
+            {
+              result = apr_array_make(pool, 32, sizeof(*lib));
+            }
+          lib = &APR_ARRAY_PUSH(result, svn_version_ext_loaded_lib_t);
+          lib->name = line->data;
+          lib->version = NULL;
+        }
+    }
+
+  svn_error_clear(svn_stream_close(stream));
+  return result;
+}
 #endif /* __linux__ */
 
 
@@ -864,7 +1077,7 @@ win32_release_name(apr_pool_t *pool)
 
 
 /* Get a list of handles of shared libs loaded by the current
-   process. Returns a NULL-terminated array alocated from POOL. */
+   process. Returns a NULL-terminated array allocated from POOL. */
 static HMODULE *
 enum_loaded_modules(apr_pool_t *pool)
 {
@@ -1112,41 +1325,71 @@ value_from_dict(CFDictionaryRef plist, C
   return value;
 }
 
-/* Return the commercial name of the OS, given the version number in
+/* Return the minor version the operating system, given the number in
    a format that matches the regular expression /^10\.\d+(\..*)?$/ */
-static const char *
-release_name_from_version(const char *osver)
+static int
+macos_minor_version(const char *osver)
 {
   char *end = NULL;
   unsigned long num = strtoul(osver, &end, 10);
 
   if (!end || *end != '.' || num != 10)
-    return NULL;
+    return -1;
 
   osver = end + 1;
   end = NULL;
   num = strtoul(osver, &end, 10);
   if (!end || (*end && *end != '.'))
-    return NULL;
+    return -1;
+
+  return (int)num;
+}
+
+/* Return the product name of the operating system. */
+static const char *
+product_name_from_minor_version(int minor, const char* product_name)
+{
+  /* We can only do this if we know the official product name. */
+  if (0 != strcmp(product_name, "Mac OS X"))
+    return product_name;
+
+  if (minor <= 7)
+    return product_name;
+
+  if (minor <= 11)
+    return "OS X";
 
-  /* See http://en.wikipedia.org/wiki/History_of_OS_X#Release_timeline */
-  switch(num)
+  return "macOS";
+}
+
+/* Return the commercial name of the operating system. */
+static const char *
+release_name_from_minor_version(int minor, const char* product_name)
+{
+  /* We can only do this if we know the official product name. */
+  if (0 == strcmp(product_name, "Mac OS X"))
     {
-    case  0: return "Cheetah";
-    case  1: return "Puma";
-    case  2: return "Jaguar";
-    case  3: return "Panther";
-    case  4: return "Tiger";
-    case  5: return "Leopard";
-    case  6: return "Snow Leopard";
-    case  7: return "Lion";
-    case  8: return "Mountain Lion";
-    case  9: return "Mavericks";
-    case 10: return "Yosemite";
-    case 11: return "El Capitan";
-    case 12: return "Sierra";
+      /* See https://en.wikipedia.org/wiki/MacOS_version_history#Releases */
+      switch(minor)
+        {
+        case  0: return "Cheetah";
+        case  1: return "Puma";
+        case  2: return "Jaguar";
+        case  3: return "Panther";
+        case  4: return "Tiger";
+        case  5: return "Leopard";
+        case  6: return "Snow Leopard";
+        case  7: return "Lion";
+        case  8: return "Mountain Lion";
+        case  9: return "Mavericks";
+        case 10: return "Yosemite";
+        case 11: return "El Capitan";
+        case 12: return "Sierra";
+        case 13: return "High Sierra";
+        case 14: return "Mojave";
+        case 15: return "Catalina";
+        }
     }
-
   return NULL;
 }
 
@@ -1169,20 +1412,23 @@ macos_release_name(apr_pool_t *pool)
                                           CFSTR("ProductBuildVersion"),
                                           pool);
       const char *release;
+      int minor_version;
 
       if (!osver)
         osver = value_from_dict(plist, CFSTR("ProductVersion"), pool);
-      release = release_name_from_version(osver);
+      minor_version = macos_minor_version(osver);
+      release = release_name_from_minor_version(minor_version, osname);
+      osname = product_name_from_minor_version(minor_version, osname);
 
       CFRelease(plist);
       return apr_psprintf(pool, "%s%s%s%s%s%s%s%s",
                           (osname ? osname : ""),
-                          (osver ? (osname ? " " : "") : ""),
-                          (osver ? osver : ""),
-                          (release ? (osname||osver ? " " : "") : ""),
+                          (release ? (osname ? " " : "") : ""),
                           (release ? release : ""),
+                          (osver ? (osname||release ? " " : "") : ""),
+                          (osver ? osver : ""),
                           (build
-                           ? (osname||osver||release ? ", " : "")
+                           ? (osname||release||osver ? ", " : "")
                            : ""),
                           (build
                            ? (server ? "server build " : "build ")

Modified: subversion/branches/addremove/subversion/libsvn_subr/temp_serializer.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_subr/temp_serializer.c?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/libsvn_subr/temp_serializer.c 
(original)
+++ subversion/branches/addremove/subversion/libsvn_subr/temp_serializer.c Sat 
May 23 14:16:56 2020
@@ -143,7 +143,7 @@ svn_temp_serializer__init(const void *so
  * been serialized to BUFFER but contains references to new objects yet to
  * serialize. The current size of the serialized data is given in
  * CURRENTLY_USED. If the allocated data buffer is actually larger, you may
- * specifiy that in CURRENTLY_ALLOCATED to prevent unnecessary allocations.
+ * specify that in CURRENTLY_ALLOCATED to prevent unnecessary allocations.
  * Otherwise, set it to 0. All allocations will be made from POOl.
  */
 svn_temp_serializer__context_t *
@@ -261,7 +261,7 @@ svn_temp_serializer__push(svn_temp_seria
     svn_stringbuf_appendbytes(context->buffer, source, struct_size);
 }
 
-/* Remove the lastest structure from the stack.
+/* Remove the latest structure from the stack.
  */
 void
 svn_temp_serializer__pop(svn_temp_serializer__context_t *context)

Modified: subversion/branches/addremove/subversion/libsvn_subr/utf.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_subr/utf.c?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/libsvn_subr/utf.c (original)
+++ subversion/branches/addremove/subversion/libsvn_subr/utf.c Sat May 23 
14:16:56 2020
@@ -72,7 +72,7 @@ typedef apr_xlate_t xlate_handle_t;
  * If there is no handle for a particular key when needed, a new is
  * handle is created and put in the cache after use.
  * This means that there will be at most N handles open for a key, where N
- * is the number of simultanous handles in use for that key. */
+ * is the number of simultaneous handles in use for that key. */
 
 typedef struct xlate_handle_node_t {
   xlate_handle_t *handle;
@@ -960,7 +960,7 @@ svn_utf__cstring_from_utf8_fuzzy(const c
 
   /* ### Check the client locale, maybe we can avoid that second
    * conversion!  See Ulrich Drepper's patch at
-   * http://subversion.tigris.org/issues/show_bug.cgi?id=807.
+   * https://issues.apache.org/jira/browse/SVN-807.
    */
 }
 

Propchange: subversion/branches/addremove/subversion/libsvn_subr/utf8proc/
------------------------------------------------------------------------------
  Reverse-merged 
/subversion/branches/wc-collate-path/subversion/libsvn_subr/utf8proc:r1405766-1480384
  Merged 
/subversion/branches/swig-py3/subversion/libsvn_subr/utf8proc:r1813660-1869353
  Merged /subversion/trunk/subversion/libsvn_subr/utf8proc:r1813173-1878056
  Merged 
/subversion/branches/shelve/subversion/libsvn_subr/utf8proc:r1802592-1815226
  Merged 
/subversion/branches/shelve-checkpoint/subversion/libsvn_subr/utf8proc:r1801593-1801923,1801970


Reply via email to