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)