Author: stsp
Date: Mon Jan 4 13:59:38 2010
New Revision: 895628
URL: http://svn.apache.org/viewvc?rev=895628&view=rev
Log:
Follow-up to r895469 and r895534:
Make svn_stream_mark() return a freshly allocated mark to the caller,
rather than remembering the mark in the stream's baton. This makes
nested calls to svn_stream_mark() possible.
Instead of overloading svn_stream_reset() for the purpose of seeking
back to a mark, introduce svn_stream_seek().
* subversion/include/svn_error_codes.h
(SVN_ERR_STREAM_MARK_NOT_SUPPORTED,
SVN_ERR_STREAM_MARK_ALREADY_SET): Remove.
(SVN_ERR_STREAM_SEEK_NOT_SUPPORTED): New.
* subversion/include/svn_io.h
(svn_stream_mark_t, svn_io_seek_fn_t): New types.
(svn_io_mark_fn_t, svn_stream_mark): Replace SET argument with MARK
and POOL arguments. Update docstring.
(svn_stream_set_seek, svn_stream_seek): Declare.
(svn_stream_reset): Revert docstring change from r895469.
* subversion/libsvn_subr/stream.c
(svn_stream_t): Add seek_fn field.
(svn_stream_mark_t): New type.
(svn_stream_create): Initialise seek_fn field.
(svn_stream_set_seek, svn_stream_seek, seek_handler_empty,
seek_handler_disown, seek_handler_apr, seek_handler_stringbuf): New.
(svn_stream_mark, mark_handler_empty, mark_handler_disown,
mark_handler_apr, mark_handler_stringbuf): Replace SET argument with
MARK and POOL arguments. Instead of remembering the mark in the stream
baton, allocate a mark in POOL and return it to the caller.
(scan_eol): Add a POOL argument to pass on to svn_stream_mark().
Call svn_stream_seek() rather than svn_stream_reset() to rewind the stream.
(svn_stream_empty, svn_stream_disown): Set seek function.
(baton_apr, stringbuf_stream_baton): Remove mark field.
(reset_handler_apr, reset_handler_stringbuf): Revert changes made in r895469.
(svn_stream_from_aprfile2, svn_stream_from_aprfile_range_readonly,
svn_stream_from_stringbuf): Track field-removal from baton_apr and
stringbuf_stream_baton, set seek function.
* subversion/tests/libsvn_subr/stream-test.c
(test_stream_mark_file, test_stream_mark_stringbuf): Rename to ...
(test_stream_seek_file, test_stream_seek_stringbuf): ... these,
and update to use new stream seeking API.
(test_funcs): Track function renaming.
Modified:
subversion/trunk/subversion/include/svn_error_codes.h
subversion/trunk/subversion/include/svn_io.h
subversion/trunk/subversion/libsvn_subr/stream.c
subversion/trunk/subversion/tests/libsvn_subr/stream-test.c
Modified: subversion/trunk/subversion/include/svn_error_codes.h
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/include/svn_error_codes.h?rev=895628&r1=895627&r2=895628&view=diff
==============================================================================
--- subversion/trunk/subversion/include/svn_error_codes.h (original)
+++ subversion/trunk/subversion/include/svn_error_codes.h Mon Jan 4 13:59:38
2010
@@ -294,14 +294,9 @@
"Stream doesn't support resetting")
/** @since New in 1.7. */
- SVN_ERRDEF(SVN_ERR_STREAM_MARK_NOT_SUPPORTED,
+ SVN_ERRDEF(SVN_ERR_STREAM_SEEK_NOT_SUPPORTED,
SVN_ERR_STREAM_CATEGORY_START + 4,
- "Stream doesn't support marking")
-
- /** @since New in 1.7. */
- SVN_ERRDEF(SVN_ERR_STREAM_MARK_ALREADY_SET,
- SVN_ERR_STREAM_CATEGORY_START + 5,
- "Mark is already set on this stream")
+ "Stream doesn't support seeking")
/* node errors */
Modified: subversion/trunk/subversion/include/svn_io.h
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/include/svn_io.h?rev=895628&r1=895627&r2=895628&view=diff
==============================================================================
--- subversion/trunk/subversion/include/svn_io.h (original)
+++ subversion/trunk/subversion/include/svn_io.h Mon Jan 4 13:59:38 2010
@@ -702,12 +702,29 @@
*/
typedef svn_error_t *(*svn_io_reset_fn_t)(void *baton);
+/* An opaque type which represents a mark on a stream.
+ *
+ * @see svn_stream_mark().
+ * @since New in 1.7.
+ */
+typedef struct svn_stream_mark_t svn_stream_mark_t;
+
/** Mark handler function for a generic stream. @see svn_stream_t and
* svn_stream_mark().
*
* @since New in 1.7.
*/
-typedef svn_error_t *(*svn_io_mark_fn_t)(void *baton, svn_boolean_t set);
+typedef svn_error_t *(*svn_io_mark_fn_t)(void *baton,
+ svn_stream_mark_t **mark,
+ apr_pool_t *pool);
+
+/** Seek handler function for a generic stream. @see svn_stream_t and
+ * svn_stream_seek().
+ *
+ * @since New in 1.7.
+ */
+typedef svn_error_t *(*svn_io_seek_fn_t)(void *baton,
+ svn_stream_mark_t *mark);
/** Line-filtering callback function for a generic stream.
* @a baton is the stream's baton.
@@ -785,6 +802,14 @@
svn_stream_set_mark(svn_stream_t *stream,
svn_io_mark_fn_t mark_fn);
+/** Set @a stream's seek function to @a seek_fn
+ *
+ * @since New in 1.7.
+ */
+void
+svn_stream_set_seek(svn_stream_t *stream,
+ svn_io_seek_fn_t seek_fn);
+
/** Set @a stream's line-filtering callback function to @a line_filter_cb
*
* @since New in 1.7.
@@ -1046,27 +1071,35 @@
* #SVN_ERR_STREAM_RESET_NOT_SUPPORTED error when the stream doesn't
* implement resetting.
*
- * If a mark has been set on the stream, the stream is reset to
- * the mark instead of its origin. @see svn_stream_mark()
- *
* @since New in 1.7.
*/
svn_error_t *
svn_stream_reset(svn_stream_t *stream);
-/** Set or clear the mark on a generic stream according to @a set.
- * If @a set is TRUE, the mark is set at the current position in
- * the stream. If @a set is FALSE, the mark is cleared.
- * This function returns the #SVN_ERR_STREAM_MARK_NOT_SUPPORTED error
- * when the stream doesn't implement marking.
- * The error #SVN_ERR_STREAM_MARK_ALREADY_SET is returned if there was
- * an attempt to set a mark without clearing an existing mark beforehand.
+/** Set a @a mark at the current position of a generic @a stream,
+ * which can later be sought back to using svn_stream_seek().
+ * The @a mark is allocated in @a pool.
+ *
+ * This function returns the #SVN_ERR_STREAM_SEEK_NOT_SUPPORTED error
+ * if the stream doesn't implement seeking.
+ *
+ * @see svn_stream_seek()
+ * @since New in 1.7.
+ */
+svn_error_t *
+svn_stream_mark(svn_stream_t *stream,
+ svn_stream_mark_t **mark,
+ apr_pool_t *pool);
+
+/* Seek to a @a mark in a generic @a stream.
+ * This function returns the #SVN_ERR_STREAM_SEEK_NOT_SUPPORTED error
+ * if the stream doesn't implement seeking.
*
- * @see svn_stream_reset()
+ * @see svn_stream_mark()
* @since New in 1.7.
*/
svn_error_t *
-svn_stream_mark(svn_stream_t *stream, svn_boolean_t set);
+svn_stream_seek(svn_stream_t *stream, svn_stream_mark_t *mark);
/** Return a writable stream which, when written to, writes to both of the
* underlying streams. Both of these streams will be closed upon closure of
Modified: subversion/trunk/subversion/libsvn_subr/stream.c
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_subr/stream.c?rev=895628&r1=895627&r2=895628&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_subr/stream.c (original)
+++ subversion/trunk/subversion/libsvn_subr/stream.c Mon Jan 4 13:59:38 2010
@@ -52,10 +52,18 @@
svn_close_fn_t close_fn;
svn_io_reset_fn_t reset_fn;
svn_io_mark_fn_t mark_fn;
+ svn_io_seek_fn_t seek_fn;
svn_io_line_filter_cb_t line_filter_cb;
svn_io_line_transformer_cb_t line_transformer_cb;
};
+/* A type which represents a mark on a stream. */
+struct svn_stream_mark_t {
+ union {
+ apr_off_t apr;
+ apr_size_t stringbuf;
+ } m;
+};
/*** Generic streams. ***/
@@ -72,6 +80,7 @@
stream->close_fn = NULL;
stream->reset_fn = NULL;
stream->mark_fn = NULL;
+ stream->seek_fn = NULL;
stream->line_filter_cb = NULL;
stream->line_transformer_cb = NULL;
return stream;
@@ -117,6 +126,12 @@
}
void
+svn_stream_set_seek(svn_stream_t *stream, svn_io_seek_fn_t seek_fn)
+{
+ stream->seek_fn = seek_fn;
+}
+
+void
svn_stream_set_line_filter_callback(svn_stream_t *stream,
svn_io_line_filter_cb_t line_filter_cb)
{
@@ -157,12 +172,22 @@
}
svn_error_t *
-svn_stream_mark(svn_stream_t *stream, svn_boolean_t set)
+svn_stream_mark(svn_stream_t *stream, svn_stream_mark_t **mark,
+ apr_pool_t *pool)
{
if (stream->mark_fn == NULL)
- return svn_error_create(SVN_ERR_STREAM_MARK_NOT_SUPPORTED, NULL, NULL);
+ return svn_error_create(SVN_ERR_STREAM_SEEK_NOT_SUPPORTED, NULL, NULL);
+
+ return stream->mark_fn(stream->baton, mark, pool);
+}
+
+svn_error_t *
+svn_stream_seek(svn_stream_t *stream, svn_stream_mark_t *mark)
+{
+ if (stream->seek_fn == NULL)
+ return svn_error_create(SVN_ERR_STREAM_SEEK_NOT_SUPPORTED, NULL, NULL);
- return stream->mark_fn(stream->baton, set);
+ return stream->seek_fn(stream->baton, mark);
}
svn_error_t *
@@ -259,11 +284,12 @@
* Set *EOL to NULL if the stream runs out before an end-of-line indicator
* is found. */
static svn_error_t *
-scan_eol(const char **eol, svn_stream_t *stream)
+scan_eol(const char **eol, svn_stream_t *stream, apr_pool_t *pool)
{
const char *eol_str;
+ svn_stream_mark_t *mark;
- SVN_ERR(svn_stream_mark(stream, TRUE));
+ SVN_ERR(svn_stream_mark(stream, &mark, pool));
eol_str = NULL;
while (! eol_str)
@@ -278,8 +304,7 @@
eol_str = svn_eol__detect_eol(buf, buf + len);
}
- SVN_ERR(svn_stream_reset(stream));
- SVN_ERR(svn_stream_mark(stream, FALSE));
+ SVN_ERR(svn_stream_seek(stream, mark));
*eol = eol_str;
@@ -324,7 +349,7 @@
if (detect_eol)
{
- SVN_ERR(scan_eol(&eol_str, stream));
+ SVN_ERR(scan_eol(&eol_str, stream, iterpool));
if (eol)
*eol = eol_str;
if (! eol_str)
@@ -500,11 +525,18 @@
}
static svn_error_t *
-mark_handler_empty(void *baton, svn_boolean_t set)
+mark_handler_empty(void *baton, svn_stream_mark_t **mark, apr_pool_t *pool)
{
return SVN_NO_ERROR;
}
+static svn_error_t *
+seek_handler_empty(void *baton, svn_stream_mark_t *mark)
+{
+ return SVN_NO_ERROR;
+}
+
+
svn_stream_t *
svn_stream_empty(apr_pool_t *pool)
{
@@ -515,6 +547,7 @@
svn_stream_set_write(stream, write_handler_empty);
svn_stream_set_reset(stream, reset_handler_empty);
svn_stream_set_mark(stream, mark_handler_empty);
+ svn_stream_set_seek(stream, seek_handler_empty);
return stream;
}
@@ -598,9 +631,15 @@
}
static svn_error_t *
-mark_handler_disown(void *baton, svn_boolean_t set)
+mark_handler_disown(void *baton, svn_stream_mark_t **mark, apr_pool_t *pool)
{
- return svn_stream_mark(baton, set);
+ return svn_stream_mark(baton, mark, pool);
+}
+
+static svn_error_t *
+seek_handler_disown(void *baton, svn_stream_mark_t *mark)
+{
+ return svn_stream_seek(baton, mark);
}
svn_stream_t *
@@ -612,6 +651,7 @@
svn_stream_set_write(s, write_handler_disown);
svn_stream_set_reset(s, reset_handler_disown);
svn_stream_set_mark(s, mark_handler_disown);
+ svn_stream_set_seek(s, seek_handler_disown);
return s;
}
@@ -627,8 +667,6 @@
* When either of these is negative, no range has been specified. */
apr_off_t start;
apr_off_t end;
-
- apr_off_t mark;
};
@@ -699,34 +737,30 @@
apr_off_t offset;
struct baton_apr *btn = baton;
- if (btn->mark >= 0)
- offset = btn->mark;
- else if (btn->start >= 0)
- offset = btn->start;
- else
- offset = 0;
+ /* If we're reading from a range, reset to the start of the range.
+ * Otherwise, reset to the start of the file. */
+ offset = btn->start >= 0 ? btn->start : 0;
return svn_io_file_seek(btn->file, APR_SET, &offset, btn->pool);
}
static svn_error_t *
-mark_handler_apr(void *baton, svn_boolean_t set)
+mark_handler_apr(void *baton, svn_stream_mark_t **mark, apr_pool_t *pool)
{
struct baton_apr *btn = baton;
-
- if (set)
- {
- if (btn->mark != -1)
- return svn_error_create(SVN_ERR_STREAM_MARK_ALREADY_SET, NULL, NULL);
- btn->mark = 0;
- SVN_ERR(svn_io_file_seek(btn->file, APR_CUR, &btn->mark, btn->pool));
- }
- else
- btn->mark = -1;
-
+ (*mark) = apr_palloc(pool, sizeof(**mark));
+ (*mark)->m.apr = 0;
+ SVN_ERR(svn_io_file_seek(btn->file, APR_CUR, &(*mark)->m.apr, btn->pool));
return SVN_NO_ERROR;
}
+static svn_error_t *
+seek_handler_apr(void *baton, svn_stream_mark_t *mark)
+{
+ struct baton_apr *btn = baton;
+ SVN_ERR(svn_io_file_seek(btn->file, APR_SET, &mark->m.apr, btn->pool));
+ return SVN_NO_ERROR;
+}
svn_error_t *
svn_stream_open_readonly(svn_stream_t **stream,
@@ -799,12 +833,12 @@
baton->pool = pool;
baton->start = -1;
baton->end = -1;
- baton->mark = -1;
stream = svn_stream_create(baton, pool);
svn_stream_set_read(stream, read_handler_apr);
svn_stream_set_write(stream, write_handler_apr);
svn_stream_set_reset(stream, reset_handler_apr);
svn_stream_set_mark(stream, mark_handler_apr);
+ svn_stream_set_seek(stream, seek_handler_apr);
if (! disown)
svn_stream_set_close(stream, close_handler_apr);
@@ -842,11 +876,11 @@
baton->pool = pool;
baton->start = start;
baton->end = end;
- baton->mark = -1;
stream = svn_stream_create(baton, pool);
svn_stream_set_read(stream, read_handler_apr);
svn_stream_set_reset(stream, reset_handler_apr);
svn_stream_set_mark(stream, mark_handler_apr);
+ svn_stream_set_seek(stream, seek_handler_apr);
if (! disown)
svn_stream_set_close(stream, close_handler_apr);
@@ -1344,7 +1378,6 @@
{
svn_stringbuf_t *str;
apr_size_t amt_read;
- apr_size_t mark;
};
static svn_error_t *
@@ -1372,25 +1405,24 @@
reset_handler_stringbuf(void *baton)
{
struct stringbuf_stream_baton *btn = baton;
- if (btn->mark != (apr_size_t)-1)
- btn->amt_read = btn->mark;
- else
- btn->amt_read = 0;
+ btn->amt_read = 0;
return SVN_NO_ERROR;
}
static svn_error_t *
-mark_handler_stringbuf(void *baton, svn_boolean_t set)
+mark_handler_stringbuf(void *baton, svn_stream_mark_t **mark, apr_pool_t *pool)
{
struct stringbuf_stream_baton *btn = baton;
- if (set)
- {
- if (btn->mark != (apr_size_t)-1)
- return svn_error_create(SVN_ERR_STREAM_MARK_ALREADY_SET, NULL, NULL);
- btn->mark = btn->amt_read;
- }
- else
- btn->mark = (apr_size_t)-1;
+ (*mark) = apr_palloc(pool, sizeof(**mark));
+ (*mark)->m.stringbuf = btn->amt_read;
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+seek_handler_stringbuf(void *baton, svn_stream_mark_t *mark)
+{
+ struct stringbuf_stream_baton *btn = baton;
+ btn->amt_read = mark->m.stringbuf;
return SVN_NO_ERROR;
}
@@ -1407,12 +1439,12 @@
baton = apr_palloc(pool, sizeof(*baton));
baton->str = str;
baton->amt_read = 0;
- baton->mark = (apr_size_t)-1;
stream = svn_stream_create(baton, pool);
svn_stream_set_read(stream, read_handler_stringbuf);
svn_stream_set_write(stream, write_handler_stringbuf);
svn_stream_set_reset(stream, reset_handler_stringbuf);
svn_stream_set_mark(stream, mark_handler_stringbuf);
+ svn_stream_set_seek(stream, seek_handler_stringbuf);
return stream;
}
Modified: subversion/trunk/subversion/tests/libsvn_subr/stream-test.c
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/libsvn_subr/stream-test.c?rev=895628&r1=895627&r2=895628&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/libsvn_subr/stream-test.c (original)
+++ subversion/trunk/subversion/tests/libsvn_subr/stream-test.c Mon Jan 4
13:59:38 2010
@@ -465,17 +465,18 @@
}
static svn_error_t *
-test_stream_mark_file(apr_pool_t *pool)
+test_stream_seek_file(apr_pool_t *pool)
{
static const char *file_data[2] = {"One", "Two"};
svn_stream_t *stream;
svn_stringbuf_t *line;
svn_boolean_t eof;
apr_file_t *f;
- static const char *fname = "test_stream_mark.txt";
+ static const char *fname = "test_stream_seek.txt";
int j;
apr_status_t status;
static const char *NL = APR_EOL_STR;
+ svn_stream_mark_t *mark;
status = apr_file_open(&f, fname, (APR_READ | APR_WRITE | APR_CREATE |
APR_TRUNCATE | APR_DELONCLOSE), APR_OS_DEFAULT, pool);
@@ -506,24 +507,17 @@
SVN_ERR(svn_stream_readline(stream, &line, NL, &eof, pool));
SVN_ERR_ASSERT(! eof && strcmp(line->data, file_data[0]) == 0);
/* Set a mark at the beginning of the second line of the file. */
- SVN_ERR(svn_stream_mark(stream, TRUE));
- /* Read the second line and then reset the stream. */
+ SVN_ERR(svn_stream_mark(stream, &mark, pool));
+ /* Read the second line and then seek back to the mark. */
SVN_ERR(svn_stream_readline(stream, &line, NL, &eof, pool));
SVN_ERR_ASSERT(! eof && strcmp(line->data, file_data[1]) == 0);
- SVN_ERR(svn_stream_reset(stream));
+ 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));
SVN_ERR_ASSERT(! eof && strcmp(line->data, file_data[1]) == 0);
- /* Clear the mark. */
- SVN_ERR(svn_stream_mark(stream, FALSE));
/* The next read should return EOF. */
SVN_ERR(svn_stream_readline(stream, &line, NL, &eof, pool));
SVN_ERR_ASSERT(eof);
- /* Reset the stream. */
- SVN_ERR(svn_stream_reset(stream));
- /* The next read should return the first line again. */
- SVN_ERR(svn_stream_readline(stream, &line, NL, &eof, pool));
- SVN_ERR_ASSERT(! eof && strcmp(line->data, file_data[0]) == 0);
SVN_ERR(svn_stream_close(stream));
@@ -531,12 +525,13 @@
}
static svn_error_t *
-test_stream_mark_stringbuf(apr_pool_t *pool)
+test_stream_seek_stringbuf(apr_pool_t *pool)
{
svn_stream_t *stream;
svn_stringbuf_t *stringbuf;
char buf[4];
apr_size_t len;
+ svn_stream_mark_t *mark;
stringbuf = svn_stringbuf_create("OneTwo", pool);
stream = svn_stream_from_stringbuf(stringbuf, pool);
@@ -544,22 +539,16 @@
SVN_ERR(svn_stream_read(stream, buf, &len));
buf[3] = '\0';
SVN_ERR_ASSERT(strcmp(buf, "One") == 0);
- SVN_ERR(svn_stream_mark(stream, TRUE));
+ SVN_ERR(svn_stream_mark(stream, &mark, pool));
len = 3;
SVN_ERR(svn_stream_read(stream, buf, &len));
buf[3] = '\0';
SVN_ERR_ASSERT(strcmp(buf, "Two") == 0);
- SVN_ERR(svn_stream_reset(stream));
+ SVN_ERR(svn_stream_seek(stream, mark));
len = 3;
SVN_ERR(svn_stream_read(stream, buf, &len));
buf[3] = '\0';
SVN_ERR_ASSERT(strcmp(buf, "Two") == 0);
- SVN_ERR(svn_stream_mark(stream, FALSE));
- SVN_ERR(svn_stream_reset(stream));
- len = 3;
- SVN_ERR(svn_stream_read(stream, buf, &len));
- buf[3] = '\0';
- SVN_ERR_ASSERT(strcmp(buf, "One") == 0);
SVN_ERR(svn_stream_close(stream));
@@ -586,9 +575,9 @@
"test stream line filtering and transforming"),
SVN_TEST_PASS2(test_stream_tee,
"test 'tee' streams"),
- SVN_TEST_PASS2(test_stream_mark_file,
- "test stream marking for files"),
- SVN_TEST_PASS2(test_stream_mark_stringbuf,
- "test stream marking for stringbufs"),
+ SVN_TEST_PASS2(test_stream_seek_file,
+ "test stream seeking for files"),
+ SVN_TEST_PASS2(test_stream_seek_stringbuf,
+ "test stream seeking for stringbufs"),
SVN_TEST_NULL
};