Author: brane
Date: Sun May 18 13:31:20 2025
New Revision: 1925668

URL: http://svn.apache.org/viewvc?rev=1925668&view=rev
Log:
On the patch-from-stream branch: Add a new stream handler function that
calculates the distance between two stream positions.

* BRANCH-README: Update contents.

* subversion/include/svn_error_codes.h
  (SVN_ERR_STREAM_SPAN_NOT_SUPPORTED,
   SVN_ERR_STREAM_OFFSET_TOO_LARGE): Add two new error codes.
* subversion/include/svn_io.h
  (svn_stream_span_fn_t,
   svn_stream_set_span,
   svn_stream_supports_span,
   svn_stream_span): New functions.
* subversion/libsvn_subr/stream.c
  (svn_stream_t::span_fn): Add new member to the private stream type.
  (svn_stream_set_span,
   svn_stream_supports_span,
   svn_stream_span): Implement the new generic stream functions.
  (span_handler_empty, svn_stream_empty): Support span for empty streams...
  (span_handler_disown, svn_stream_disown): ...and for disowned streams...
  (span_handler_apr, make_stream_from_apr_file): ...and file streams.
  (stringbuf_stream_mark, string_stream_mark): Remove. Replace with...
  (mark_str): ... this. These were identical copy/pasted structures.
  (mark_handler_stringbuf, seek_handler_stringbuf): Use mark_str.
  (mark_handler_string, seek_handler_string): And here, too.
  (off_t_can_not_represent): New helper function for type conversions.
  (span_handler_str,
   svn_stream_from_stringbuf,
   svn_stream_from_string): Support span for string and stringbuf streams...
  (span_handler_lazyopen, svn_stream_lazyopen_create): ...and lazyopen.
* subversion/libsvn_subr/subst.c
  (translated_stream_span, stream_translated): Support span.

* subversion/libsvn_repos/config_file.c
  (span_handler_rep, representation_stream): Support span.

* subversion/tests/libsvn_subr/stream-test.c
  (test_stream_seek_file,
   test_stream_seek_stringbuf,
   test_stream_seek_translated,
   test_stream_compressed_empty_file): Add tests for stream span.

Modified:
    subversion/branches/patch-from-stream/BRANCH-README
    subversion/branches/patch-from-stream/subversion/include/svn_error_codes.h
    subversion/branches/patch-from-stream/subversion/include/svn_io.h
    subversion/branches/patch-from-stream/subversion/libsvn_repos/config_file.c
    subversion/branches/patch-from-stream/subversion/libsvn_subr/stream.c
    subversion/branches/patch-from-stream/subversion/libsvn_subr/subst.c
    
subversion/branches/patch-from-stream/subversion/tests/libsvn_subr/stream-test.c

Modified: subversion/branches/patch-from-stream/BRANCH-README
URL: 
http://svn.apache.org/viewvc/subversion/branches/patch-from-stream/BRANCH-README?rev=1925668&r1=1925667&r2=1925668&view=diff
==============================================================================
--- subversion/branches/patch-from-stream/BRANCH-README (original)
+++ subversion/branches/patch-from-stream/BRANCH-README Sun May 18 13:31:20 2025
@@ -1,6 +1,21 @@
 Use streams instead of APR files to read patch files.
 =====================================================
 
-2025-05-16: The patch parser currently uses apr_file_t to read
-and parse patch files. Convert to usint svn_stream_t instead,
+2025-05-16: The patch parser currently uses APR files to read
+and parse patch files. Convert it to use SVN streams instead,
 as it's more flexible and doesn't strictly rely on on-disk files.
+
+
+ISSUES:
+  - Reading patches currently relies heavily on seeking in the file.
+    This is really supported only in file-based and string-based streams,
+    and not even all of those (e.g., (de)compressed and tee'd streams
+    don't support seek even if there's an underlying file). That makes
+    reading patches from streams less flexible than it could be.
+
+    Still, by converting to reading from streams, we're not reducing
+    existing features; all current use cases for reading patches remain
+    supported, because file-based streams always support mark and seek.
+
+    And now, they also support span, i.e., finding the distance between
+    two stream marks, just like for two file positions.

Modified: 
subversion/branches/patch-from-stream/subversion/include/svn_error_codes.h
URL: 
http://svn.apache.org/viewvc/subversion/branches/patch-from-stream/subversion/include/svn_error_codes.h?rev=1925668&r1=1925667&r2=1925668&view=diff
==============================================================================
--- subversion/branches/patch-from-stream/subversion/include/svn_error_codes.h 
(original)
+++ subversion/branches/patch-from-stream/subversion/include/svn_error_codes.h 
Sun May 18 13:31:20 2025
@@ -334,6 +334,16 @@ SVN_ERROR_START
              SVN_ERR_STREAM_CATEGORY_START + 4,
              "Stream doesn't support this capability")
 
+  /** @since New in 1.15. */
+  SVN_ERRDEF(SVN_ERR_STREAM_SPAN_NOT_SUPPORTED,
+             SVN_ERR_STREAM_CATEGORY_START + 5,
+             "Stream doesn't support calculating offsets")
+
+  /** @since New in 1.15. */
+  SVN_ERRDEF(SVN_ERR_STREAM_OFFSET_TOO_LARGE,
+             SVN_ERR_STREAM_CATEGORY_START + 6,
+             "The offset between two stream positions is too large")
+
   /* node errors */
 
   SVN_ERRDEF(SVN_ERR_NODE_UNKNOWN_KIND,

Modified: subversion/branches/patch-from-stream/subversion/include/svn_io.h
URL: 
http://svn.apache.org/viewvc/subversion/branches/patch-from-stream/subversion/include/svn_io.h?rev=1925668&r1=1925667&r2=1925668&view=diff
==============================================================================
--- subversion/branches/patch-from-stream/subversion/include/svn_io.h (original)
+++ subversion/branches/patch-from-stream/subversion/include/svn_io.h Sun May 
18 13:31:20 2025
@@ -910,6 +910,16 @@ typedef svn_error_t *(*svn_stream_mark_f
 typedef svn_error_t *(*svn_stream_seek_fn_t)(void *baton,
                                              const svn_stream_mark_t *mark);
 
+/** Span handler function for a generic stream. @see svn_stream_t and
+ * svn_stream_span().
+ *
+ * @since New in 1.15.
+ */
+typedef svn_error_t *(*svn_stream_span_fn_t)(
+    void *baton, apr_off_t *offset,
+    const svn_stream_mark_t *first_mark,
+    const svn_stream_mark_t *second_mark);
+
 /** Poll handler for generic streams that support incomplete reads, @see
  * svn_stream_t and svn_stream_data_available().
  *
@@ -995,6 +1005,14 @@ void
 svn_stream_set_seek(svn_stream_t *stream,
                     svn_stream_seek_fn_t seek_fn);
 
+/** Set @a stream's span function to @a span_fn
+ *
+ * @since New in 1.15.
+ */
+void
+svn_stream_set_span(svn_stream_t *stream,
+                    svn_stream_span_fn_t span_fn);
+
 /** Set @a stream's data available function to @a data_available_fn
  *
  * @since New in 1.9.
@@ -1393,6 +1411,14 @@ svn_stream_supports_mark(svn_stream_t *s
 svn_boolean_t
 svn_stream_supports_seek(svn_stream_t *stream);
 
+/** Returns @c TRUE if the generic @a stream supports svn_stream_span().
+ *
+ * @see svn_stream_span()
+ * @since New in 1.15.
+ */
+svn_boolean_t
+svn_stream_supports_span(svn_stream_t *stream);
+
 /** Returns @c TRUE if the generic @a stream supports svn_stream_reset().
  *
  * @see svn_stream_reset()
@@ -1427,6 +1453,32 @@ svn_stream_mark(svn_stream_t *stream,
 svn_error_t *
 svn_stream_seek(svn_stream_t *stream, const svn_stream_mark_t *mark);
 
+/** Calculate the offset between two positions in a generic @a stream.
+ *
+ * The @a stream must support svn_stream_mark(), but that does not guarantee
+ * that the offset between two positions in the stream is well defined. The
+ * function returns the #SVN_ERR_STREAM_SPAN_NOT_SUPPORTED in this case.
+ *
+ * It's possible for a stream to support svn_stream_mark() and
+ * svn_stream_span() but not svn_stream_seek() or svn_stream_reset().
+ * This is the case, for example, for compressed stream wrappers, where
+ * a seek would have to roll back some magic internal compression state,
+ * but for calculating an offset we only have to keep track of the number
+ * of bytes read from or written to the stream.
+ *
+ * If the offset can be calculated but is too large to represent with an
+ * apr_off_t, this function returns #SVN_ERR_STREAM_OFFSET_TOO_LARGE.
+ *
+ * The returned @a offset can be negative.
+ *
+ * @see svn_stream_mark()
+ * @since New in 1.15
+ */
+svn_error_t *
+svn_stream_span(apr_off_t *offset, svn_stream_t *stream,
+                const svn_stream_mark_t *first_mark,
+                const svn_stream_mark_t *second_mark);
+
 /** When a stream supports polling for available data, obtain a boolean
  * indicating whether data is waiting to be read. If the stream doesn't
  * support polling this function returns a #SVN_ERR_STREAM_NOT_SUPPORTED

Modified: 
subversion/branches/patch-from-stream/subversion/libsvn_repos/config_file.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/patch-from-stream/subversion/libsvn_repos/config_file.c?rev=1925668&r1=1925667&r2=1925668&view=diff
==============================================================================
--- subversion/branches/patch-from-stream/subversion/libsvn_repos/config_file.c 
(original)
+++ subversion/branches/patch-from-stream/subversion/libsvn_repos/config_file.c 
Sun May 18 13:31:20 2025
@@ -110,6 +110,18 @@ seek_handler_rep(void *baton, const svn_
 }
 
 static svn_error_t *
+span_handler_rep(void *baton, apr_off_t *offset,
+                 const svn_stream_mark_t *first_mark,
+                 const svn_stream_mark_t *second_mark)
+{
+  presentation_stream_baton_t *b = baton;
+  SVN_ERR(auto_open_inner_stream(b));
+
+  return svn_error_trace(svn_stream_span(offset, b->inner,
+                                         first_mark, second_mark));
+}
+
+static svn_error_t *
 skip_handler_rep(void *baton, apr_size_t len)
 {
   presentation_stream_baton_t *b = baton;
@@ -160,6 +172,7 @@ representation_stream(svn_fs_root_t *roo
   svn_stream_set_mark(stream, mark_handler_rep);
   svn_stream_set_seek(stream, seek_handler_rep);
   svn_stream_set_skip(stream, skip_handler_rep);
+  svn_stream_set_span(stream, span_handler_rep);
   svn_stream_set_data_available(stream, data_available_handler_rep);
   svn_stream_set_readline(stream, readline_handler_rep);
   return stream;

Modified: subversion/branches/patch-from-stream/subversion/libsvn_subr/stream.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/patch-from-stream/subversion/libsvn_subr/stream.c?rev=1925668&r1=1925667&r2=1925668&view=diff
==============================================================================
--- subversion/branches/patch-from-stream/subversion/libsvn_subr/stream.c 
(original)
+++ subversion/branches/patch-from-stream/subversion/libsvn_subr/stream.c Sun 
May 18 13:31:20 2025
@@ -63,6 +63,7 @@ struct svn_stream_t {
   svn_stream_data_available_fn_t data_available_fn;
   svn_stream_readline_fn_t readline_fn;
   apr_file_t *file; /* Maybe NULL */
+  svn_stream_span_fn_t span_fn;
 };
 
 
@@ -132,6 +133,13 @@ svn_stream_set_seek(svn_stream_t *stream
 }
 
 void
+svn_stream_set_span(svn_stream_t *stream,
+                    svn_stream_span_fn_t span_fn)
+{
+  stream->span_fn = span_fn;
+}
+
+void
 svn_stream_set_data_available(svn_stream_t *stream,
                               svn_stream_data_available_fn_t data_available_fn)
 {
@@ -242,6 +250,12 @@ svn_stream_supports_seek(svn_stream_t *s
 }
 
 svn_boolean_t
+svn_stream_supports_span(svn_stream_t *stream)
+{
+  return stream->span_fn != NULL;
+}
+
+svn_boolean_t
 svn_stream_supports_reset(svn_stream_t *stream)
 {
   return svn_stream_supports_seek(stream);
@@ -267,6 +281,19 @@ svn_stream_seek(svn_stream_t *stream, co
 }
 
 svn_error_t *
+svn_stream_span(apr_off_t *offset,
+                svn_stream_t *stream,
+                const svn_stream_mark_t *first_mark,
+                const svn_stream_mark_t *second_mark)
+{
+  if (stream->span_fn == NULL)
+    return svn_error_create(SVN_ERR_STREAM_SPAN_NOT_SUPPORTED, NULL, NULL);
+
+  return svn_error_trace(stream->span_fn(stream->baton, offset,
+                                         first_mark, second_mark));
+}
+
+svn_error_t *
 svn_stream_data_available(svn_stream_t *stream,
                           svn_boolean_t *data_available)
 {
@@ -531,7 +558,14 @@ seek_handler_empty(void *baton, const sv
   return SVN_NO_ERROR;
 }
 
-
+static svn_error_t *
+span_handler_empty(void *baton, apr_off_t *offset,
+                   const svn_stream_mark_t *first_mark,
+                   const svn_stream_mark_t *second_mark)
+{
+  *offset = 0;
+  return SVN_NO_ERROR;
+}
 
 svn_stream_t *
 svn_stream_empty(apr_pool_t *pool)
@@ -543,6 +577,7 @@ svn_stream_empty(apr_pool_t *pool)
   svn_stream_set_write(stream, write_handler_empty);
   svn_stream_set_mark(stream, mark_handler_empty);
   svn_stream_set_seek(stream, seek_handler_empty);
+  svn_stream_set_span(stream, span_handler_empty);
   return stream;
 }
 
@@ -644,6 +679,15 @@ seek_handler_disown(void *baton, const s
 }
 
 static svn_error_t *
+span_handler_disown(void *baton, apr_off_t *offset,
+                    const svn_stream_mark_t *first_mark,
+                    const svn_stream_mark_t *second_mark)
+{
+  return svn_error_trace(svn_stream_span(offset, baton,
+                                         first_mark, second_mark));
+}
+
+static svn_error_t *
 data_available_disown(void *baton, svn_boolean_t *data_available)
 {
   return svn_error_trace(svn_stream_data_available(baton, data_available));
@@ -674,6 +718,8 @@ svn_stream_disown(svn_stream_t *stream,
     svn_stream_set_mark(s, mark_handler_disown);
   if (svn_stream_supports_seek(stream))
     svn_stream_set_seek(s, seek_handler_disown);
+  if (svn_stream_supports_span(stream))
+    svn_stream_set_span(s, span_handler_disown);
   svn_stream_set_data_available(s, data_available_disown);
   svn_stream_set_readline(s, readline_handler_disown);
 
@@ -822,6 +868,20 @@ seek_handler_apr(void *baton, const svn_
 }
 
 static svn_error_t *
+span_handler_apr(void *baton, apr_off_t *offset,
+                 const svn_stream_mark_t *first_mark,
+                 const svn_stream_mark_t *second_mark)
+{
+  apr_off_t first_offset = ((first_mark == NULL) ? 0
+                            : ((const struct mark_apr *)first_mark)->off);
+  apr_off_t second_offset = ((second_mark == NULL) ? 0
+                             : ((const struct mark_apr *)second_mark)->off);
+
+  *offset = second_offset - first_offset;
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
 data_available_handler_apr(void *baton, svn_boolean_t *data_available)
 {
   struct baton_apr *btn = baton;
@@ -1100,6 +1160,7 @@ make_stream_from_apr_file(apr_file_t *fi
       svn_stream_set_skip(stream, skip_handler_apr);
       svn_stream_set_mark(stream, mark_handler_apr);
       svn_stream_set_seek(stream, seek_handler_apr);
+      svn_stream_set_span(stream, span_handler_apr);
       svn_stream_set_readline(stream, readline_handler_apr);
     }
 
@@ -1628,11 +1689,51 @@ struct stringbuf_stream_baton
   apr_size_t amt_read;
 };
 
-/* svn_stream_mark_t for streams backed by stringbufs. */
-struct stringbuf_stream_mark {
+/* svn_stream_mark_t for streams backed by stringbufs and strings. */
+struct mark_str {
     apr_size_t pos;
 };
 
+/* Try to check if an apr_size_t can be safely converted to an apr_off_t. */
+static APR_INLINE svn_boolean_t
+off_t_can_not_represent(apr_size_t size)
+{
+#ifdef APR_OFF_MAX
+  static const apr_off_t off_t_max = APR_OFF_MAX;
+#else
+  static const apr_off_t off_t_max =
+      (sizeof(apr_off_t) == sizeof(apr_int32_t) ? APR_INT32_MAX
+       : (sizeof(apr_off_t) == sizeof(apr_int64_t) ? APR_INT64_MAX
+          : 0 /* Maybe, someday, APR will have an int128_t. */));
+#endif
+
+  /* Any sane compiler should resolve this at compile time. */
+  if (sizeof(off_t_max) > sizeof(size))
+    return FALSE;
+
+  if (SVN__PREDICT_FALSE(off_t_max == 0))
+    SVN_ERR_ASSERT_NO_RETURN(off_t_max != 0);
+  return size > off_t_max;
+}
+
+static svn_error_t* span_handler_str(void *baton, apr_off_t *offset,
+                                     const svn_stream_mark_t *first_mark,
+                                     const svn_stream_mark_t *second_mark)
+{
+  const apr_size_t pos1 = ((first_mark == NULL) ? 0
+                           : ((const struct mark_str*)first_mark)->pos);
+  const apr_size_t pos2 = ((second_mark == NULL) ? 0
+                           : ((const struct mark_str *)second_mark)->pos);
+  const svn_boolean_t negative = pos2 < pos1;
+  const apr_size_t scale = negative ? pos1 - pos2 : pos2 - pos1;
+
+  if (SVN__PREDICT_FALSE(off_t_can_not_represent(scale)))
+    return svn_error_create(SVN_ERR_STREAM_OFFSET_TOO_LARGE, NULL, NULL);
+
+  *offset = negative ? -(apr_off_t)scale : (apr_off_t)scale;
+  return SVN_NO_ERROR;
+}
+
 static svn_error_t *
 read_handler_stringbuf(void *baton, char *buffer, apr_size_t *len)
 {
@@ -1669,13 +1770,13 @@ static svn_error_t *
 mark_handler_stringbuf(void *baton, svn_stream_mark_t **mark, apr_pool_t *pool)
 {
   struct stringbuf_stream_baton *btn;
-  struct stringbuf_stream_mark *stringbuf_stream_mark;
+  struct mark_str *marker;
 
   btn = baton;
 
-  stringbuf_stream_mark = apr_palloc(pool, sizeof(*stringbuf_stream_mark));
-  stringbuf_stream_mark->pos = btn->amt_read;
-  *mark = (svn_stream_mark_t *)stringbuf_stream_mark;
+  marker = apr_palloc(pool, sizeof(*marker));
+  marker->pos = btn->amt_read;
+  *mark = (svn_stream_mark_t *)marker;
   return SVN_NO_ERROR;
 }
 
@@ -1686,10 +1787,8 @@ seek_handler_stringbuf(void *baton, cons
 
   if (mark != NULL)
     {
-      const struct stringbuf_stream_mark *stringbuf_stream_mark;
-
-      stringbuf_stream_mark = (const struct stringbuf_stream_mark *)mark;
-      btn->amt_read = stringbuf_stream_mark->pos;
+      const struct mark_str *const marker = (const struct mark_str *)mark;
+      btn->amt_read = marker->pos;
     }
   else
     btn->amt_read = 0;
@@ -1756,6 +1855,7 @@ svn_stream_from_stringbuf(svn_stringbuf_
   svn_stream_set_write(stream, write_handler_stringbuf);
   svn_stream_set_mark(stream, mark_handler_stringbuf);
   svn_stream_set_seek(stream, seek_handler_stringbuf);
+  svn_stream_set_span(stream, span_handler_str);
   svn_stream_set_data_available(stream, data_available_handler_stringbuf);
   svn_stream_set_readline(stream, readline_handler_stringbuf);
   return stream;
@@ -1767,11 +1867,6 @@ struct string_stream_baton
   apr_size_t amt_read;
 };
 
-/* svn_stream_mark_t for streams backed by stringbufs. */
-struct string_stream_mark {
-    apr_size_t pos;
-};
-
 static svn_error_t *
 read_handler_string(void *baton, char *buffer, apr_size_t *len)
 {
@@ -1788,7 +1883,7 @@ static svn_error_t *
 mark_handler_string(void *baton, svn_stream_mark_t **mark, apr_pool_t *pool)
 {
   struct string_stream_baton *btn;
-  struct string_stream_mark *marker;
+  struct mark_str *marker;
 
   btn = baton;
 
@@ -1805,9 +1900,7 @@ seek_handler_string(void *baton, const s
 
   if (mark != NULL)
     {
-      const struct string_stream_mark *marker;
-
-      marker = (const struct string_stream_mark *)mark;
+      const struct mark_str *const marker = (const struct mark_str *)mark;
       btn->amt_read = marker->pos;
     }
   else
@@ -1885,6 +1978,7 @@ svn_stream_from_string(const svn_string_
   svn_stream_set_mark(stream, mark_handler_string);
   svn_stream_set_seek(stream, seek_handler_string);
   svn_stream_set_skip(stream, skip_handler_string);
+  svn_stream_set_span(stream, span_handler_str);
   svn_stream_set_data_available(stream, data_available_handler_string);
   svn_stream_set_readline(stream, readline_handler_string);
   return stream;
@@ -2124,6 +2218,21 @@ seek_handler_lazyopen(void *baton,
   return SVN_NO_ERROR;
 }
 
+/* Implements svn_stream_span_fn_t */
+static svn_error_t *
+span_handler_lazyopen(void *baton, apr_off_t *offset,
+                      const svn_stream_mark_t *first_mark,
+                      const svn_stream_mark_t *second_mark)
+{
+  lazyopen_baton_t *b = baton;
+
+  SVN_ERR(lazyopen_if_unopened(b));
+  SVN_ERR(svn_stream_span(offset, b->real_stream,
+                          first_mark, second_mark));
+
+  return SVN_NO_ERROR;
+}
+
 static svn_error_t *
 data_available_handler_lazyopen(void *baton,
                                 svn_boolean_t *data_available)
@@ -2173,6 +2282,7 @@ svn_stream_lazyopen_create(svn_stream_la
   svn_stream_set_close(stream, close_handler_lazyopen);
   svn_stream_set_mark(stream, mark_handler_lazyopen);
   svn_stream_set_seek(stream, seek_handler_lazyopen);
+  svn_stream_set_span(stream, span_handler_lazyopen);
   svn_stream_set_data_available(stream, data_available_handler_lazyopen);
   svn_stream_set_readline(stream, readline_handler_lazyopen);
 

Modified: subversion/branches/patch-from-stream/subversion/libsvn_subr/subst.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/patch-from-stream/subversion/libsvn_subr/subst.c?rev=1925668&r1=1925667&r2=1925668&view=diff
==============================================================================
--- subversion/branches/patch-from-stream/subversion/libsvn_subr/subst.c 
(original)
+++ subversion/branches/patch-from-stream/subversion/libsvn_subr/subst.c Sun 
May 18 13:31:20 2025
@@ -1432,6 +1432,24 @@ translated_stream_seek(void *baton, cons
   return SVN_NO_ERROR;
 }
 
+/* Implements svn_stream_span_fn_t.
+   NOTE: Returns the distance in the wrapped stream, not in the
+         translated data. */
+static svn_error_t *
+translated_stream_span(void *baton, apr_off_t *offset,
+                       const svn_stream_mark_t *first_mark,
+                       const svn_stream_mark_t *second_mark)
+{
+  struct translated_stream_baton *b = baton;
+  const mark_translated_t *mt1 = (const mark_translated_t *)first_mark;
+  const mark_translated_t *mt2 = (const mark_translated_t *)second_mark;
+  return svn_error_trace(
+      svn_stream_span(offset, b->stream,
+                      mt1 != NULL ? mt1->mark : NULL,
+                      mt2 != NULL ? mt2->mark : NULL));
+}
+
+
 svn_error_t *
 svn_subst_read_specialfile(svn_stream_t **stream,
                            const char *path,
@@ -1545,6 +1563,8 @@ stream_translated(svn_stream_t *stream,
         svn_stream_set_mark(s, translated_stream_mark);
       if (svn_stream_supports_seek(stream))
         svn_stream_set_seek(s, translated_stream_seek);
+      if (svn_stream_supports_span(stream))
+        svn_stream_set_span(s, translated_stream_span);
 
       return s;
     }

Modified: 
subversion/branches/patch-from-stream/subversion/tests/libsvn_subr/stream-test.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/patch-from-stream/subversion/tests/libsvn_subr/stream-test.c?rev=1925668&r1=1925667&r2=1925668&view=diff
==============================================================================
--- 
subversion/branches/patch-from-stream/subversion/tests/libsvn_subr/stream-test.c
 (original)
+++ 
subversion/branches/patch-from-stream/subversion/tests/libsvn_subr/stream-test.c
 Sun May 18 13:31:20 2025
@@ -262,7 +262,8 @@ test_stream_seek_file(apr_pool_t *pool)
   int j;
   apr_status_t status;
   static const char *NL = APR_EOL_STR;
-  svn_stream_mark_t *mark;
+  svn_stream_mark_t *mark, *mark2;
+  apr_off_t offset;
 
   status = apr_file_open(&f, fname, (APR_READ | APR_WRITE | APR_CREATE |
                          APR_TRUNCATE | APR_DELONCLOSE), APR_OS_DEFAULT, pool);
@@ -297,6 +298,11 @@ test_stream_seek_file(apr_pool_t *pool)
   /* Read the second line and then seek back to the mark. */
   SVN_ERR(svn_stream_readline(stream, &line, NL, &eof, pool));
   SVN_TEST_ASSERT(! eof && strcmp(line->data, file_data[1]) == 0);
+  /* Check how far we read before seeking. */
+  SVN_ERR(svn_stream_mark(stream, &mark2, pool));
+  SVN_ERR(svn_stream_span(&offset, stream, mark, mark2));
+  SVN_TEST_ASSERT(offset == strlen(line->data) + strlen(NL));
+  /* Ok, carry on... */
   SVN_ERR(svn_stream_seek(stream, mark));
   /* The next read should return the second line again. */
   SVN_ERR(svn_stream_readline(stream, &line, NL, &eof, pool));
@@ -328,7 +334,8 @@ test_stream_seek_stringbuf(apr_pool_t *p
   svn_stringbuf_t *stringbuf;
   char buf[4];
   apr_size_t len;
-  svn_stream_mark_t *mark;
+  svn_stream_mark_t *mark, *mark2;
+  apr_off_t offset;
 
   stringbuf = svn_stringbuf_create("OneTwo", pool);
   stream = svn_stream_from_stringbuf(stringbuf, pool);
@@ -350,6 +357,10 @@ test_stream_seek_stringbuf(apr_pool_t *p
   /* Go back to the begin of last word and try to skip some of it */
   SVN_ERR(svn_stream_seek(stream, mark));
   SVN_ERR(svn_stream_skip(stream, 2));
+  /* Check that we actually skipped that far. */
+  SVN_ERR(svn_stream_mark(stream, &mark2, pool));
+  SVN_ERR(svn_stream_span(&offset, stream, mark, mark2));
+  SVN_TEST_ASSERT(offset == 2);
   /* The remaining line should be empty */
   len = 3;
   SVN_ERR(svn_stream_read_full(stream, buf, &len));
@@ -369,7 +380,8 @@ test_stream_seek_translated(apr_pool_t *
   svn_stringbuf_t *stringbuf;
   char buf[44]; /* strlen("One$MyKeyword: my keyword was expanded $Two") + \0 
*/
   apr_size_t len;
-  svn_stream_mark_t *mark;
+  svn_stream_mark_t *mark, *mark2;
+  apr_off_t offset;
   apr_hash_t *keywords;
   svn_string_t *keyword_val;
 
@@ -381,6 +393,7 @@ test_stream_seek_translated(apr_pool_t *
   translated_stream = svn_subst_stream_translated(stream, APR_EOL_STR,
                                                   FALSE, keywords, TRUE, pool);
   /* Seek from outside of keyword to inside of keyword. */
+  SVN_ERR(svn_stream_mark(translated_stream, &mark2, pool));
   len = 25;
   SVN_ERR(svn_stream_read_full(translated_stream, buf, &len));
   SVN_TEST_ASSERT(len == 25);
@@ -388,6 +401,10 @@ test_stream_seek_translated(apr_pool_t *
   SVN_TEST_STRING_ASSERT(buf, "One$MyKeyword: my keyword");
   SVN_ERR(svn_stream_mark(translated_stream, &mark, pool));
   SVN_ERR(svn_stream_reset(translated_stream));
+  SVN_ERR(svn_stream_span(&offset, translated_stream, mark, mark2));
+  /* This is the distance in the untranslated stream, so the length of
+     that "One$MyKeyword$Two" that was read from there. */
+  SVN_TEST_ASSERT(offset == -17);
   SVN_ERR(svn_stream_seek(translated_stream, mark));
   len = 4;
   SVN_ERR(svn_stream_read_full(translated_stream, buf, &len));
@@ -524,6 +541,7 @@ test_stream_compressed_empty_file(apr_po
                                  svn_io_file_del_on_pool_cleanup,
                                  pool, pool));
   stream = svn_stream_compressed(empty_file_stream, pool);
+  SVN_TEST_ASSERT(!svn_stream_supports_span(stream));
   len = sizeof(buf);
   SVN_ERR(svn_stream_read_full(stream, buf, &len));
   if (len > 0)


Reply via email to