On Thu, Jul 08, 2010 at 09:52:51AM +0100, Julian Foad wrote:
> Hi Stefan. I've just started looking at this. Overall impression is it
> looks like you've done it very well - thank you!
>
> Could you possibly get the readline_detect_eol() API changes out of this
> patch, and make them in a separate patch either before or after this?
> Or if that change belongs in this patch, please explain why in the log
> msg.
It's actually not needed. I think I added it trying to make the
parameter list of svn_io_readline_fn_t match the ones of
svn_stream_readline and svn_stream_readline_detect_eol as closely
as possible.
Looking at it again, adding another parameter to svn_io_readline_fn_t
which says whether the EOL should be detected is much cleaner.
This simplifies implementations, and allows callers of
svn_stream_readline_detect_eol to be lazy about initialising the
eol output parameter.
Updated diff (verified by running just the patch tests which exercise
stream_readline a lot) and updated log message below. Thanks!
[[[
Fix issue #3555, 'Remove the "line_filter" and "line_transformer" callbacks
from svn_stream_t'.
Make svn_stream_readline() a virtual method of svn_stream_t,
and provide custom implementations of readline methods in the diff
parsing code (which is the only place where we need this right now).
* subversion/include/svn_io.h
(svn_io_line_filter_cb_t, svn_io_line_transformer_cb_t,
svn_stream_set_line_filter_callback,
svn_stream_set_line_transformer_callback): Remove.
(svn_io_readline_fn_t, svn_stream_set_readline): Declare.
(svn_stream_readline): Adjust docstring.
(svn_stream_readline_detect_eol): Switch to dual-pool paradigm and
document that the stream needs to support mark and seek.
* subversion/libsvn_diff/parse-diff.c
(original_line_filter, modified_line_filter, remove_leading_char_transformer,
reverse_diff_transformer): Remove.
(hunk_text_stream_baton, read_handler_hunk_text, write_handler_hunk_text,
close_handler_hunk_text, reset_handler_hunk_text, mark_handler_hunk_text,
seek_handler_hunk_text, scan_eol, readline_handler_hunk_text,
stream_hunk_text, stream_hunk_text_original, stream_hunk_text_modified):
New. Implementation of a stream which provides a special readline
method to read original/modified texts of hunks from a patch file stream.
(reverse_diff_text_stream_baton, read_handler_reverse_diff_text,
write_handler_reverse_diff_text, close_handler_reverse_diff_text,
reset_handler_reverse_diff_text, mark_handler_reverse_diff_text,
seek_handler_reverse_diff_text, readline_handler_reverse_diff_text,
stream_reverse_diff_text): New. Implementation of a stream which
provides a special readline method which reverses unidiff data read
from the wrapped stream.
(parse_next_hunk): Track svn_stream_readline_detect_eol() dual-pool change.
Add a comment explaining why the patch file gets opened multiple
times (drive-by fix because this confused me at first).
Instead of installing line-filter/transformation callbacks on
streams, wrap streams with appropriate wrapper streams.
* subversion/libsvn_subr/stream.c
(struct svn_stream_t): Replace line_filter_cb and line_transformer_cb
members with readline_fn member.
(svn_stream_create): Track changes to svn_stream_t.
(svn_stream_set_line_filter_callback,
svn_stream_set_line_transformer_callback,
line_filter, line_transformer): Remove.
(scan_eol): Tweak argument list for use within a stream method.
This function can no longer expect a stream, so pass a baton
and a set of required stream methods instead.
(stream_readline): Make this an svn_io_readline_fn_t implementation.
Remove handling of line filters/transformers.
(svn_stream_readline): Instead of calling the stream_readline() helper
directly, call a custom readline implementation if one is set on the
stream. If no custom implementation is provided, fall back to the
stream_readline() helper function to preserve compatibility with 1.6.x.
(svn_stream_readline_detect_eol): As previous, and ensure that
the stream has mark/seek support as it is needed for EOL detection.
(readline_handler_empty): Custom readline handler for the empty stream.
(svn_stream_empty, svn_stream_disown, svn_stream_from_aprfile2,
svn_stream_from_aprfile_range_readonly, svn_stream_compressed,
svn_stream_checksummed2, svn_stream_checksummed, svn_stream_from_stringbuf,
svn_stream_from_string): Set a readline method.
* subversion/libsvn_client/patch.c
(read_line, match_hunk, reject_hunk, apply_hunk): Pass two pools to
svn_stream_readline_detect_eol().
* subversion/tests/libsvn_subr/stream-test.c
(line_filter, test_stream_line_filter, line_transformer,
test_stream_line_transformer,
test_stream_line_filter_and_transformer): Remove these tests.
(test_funcs): Remove removed tests.
]]]
Index: subversion/include/svn_io.h
===================================================================
--- subversion/include/svn_io.h (revision 961349)
+++ subversion/include/svn_io.h (working copy)
@@ -780,40 +780,39 @@ typedef svn_error_t *(*svn_io_mark_fn_t)(void *bat
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.
- * @see svn_stream_t, svn_stream_set_baton() and svn_stream_readline().
+/** Line-reading handler function for a generic stream.
*
- * @since New in 1.7.
- */
-typedef svn_error_t *(*svn_io_line_filter_cb_t)(svn_boolean_t *filtered,
- const char *line,
- void *baton,
- apr_pool_t *scratch_pool);
-
-/** A callback function, invoked by svn_stream_readline(), which can perform
- * arbitary transformations on the line before it is passed back to the caller
- * of svn_stream_readline().
+ * Allocate @a *stringbuf in @a result_pool, and read into it one line
+ * from the stream. @a baton is the stream's baton.
+ * If @a detect_eol is @c FALSE, @a *eol is used as the expected line
+ * terminator. If @a detect_eol is @c TRUE, the line-terminator is
+ * detected automatically and stored in @a *eol if @a eol is not NULL.
+ * If EOF is reached and the stream does not end with a newline character,
+ * and @a eol is not NULL, @a *eol is set to NULL.
*
- * Returns a transformed stringbuf in @a buf, allocated in @a result_pool.
- * This callback gets invoked on lines which were not filtered by the
- * line-filtering callback function.
+ * @a mark_fn and @a seek_fn are required to be non-NULL if the end-of-line
+ * indicator is to be detected automatically. Else, they may be NULL.
*
- * Implementations should always at least return an empty stringbuf.
- * It is a fatal error if an implementation returns @a *buf as NULL.
+ * The line-terminator is read from the stream, but is not added to
+ * the end of the stringbuf. Instead, the stringbuf ends with a usual '\\0'.
*
- * @a baton is the stream's baton.
+ * If @a stream runs out of bytes before encountering a line-terminator,
+ * then set @a *eof to @c TRUE, otherwise set @a *eof to @c FALSE.
*
- * @see svn_stream_t, svn_stream_set_baton(), svn_io_line_filter_cb_t and
- * svn_stream_readline().
+ * Temporary allocations will be performed in @a scratch_pool.
*
- * @since New in 1.7.
- */
-typedef svn_error_t *(*svn_io_line_transformer_cb_t)(svn_stringbuf_t **buf,
- const char *line,
- void *baton,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool);
+ * @see svn_stream_readline and svn_stream_readline_detect_eol.
+ * @since New in 1.7. */
+typedef svn_error_t *(*svn_io_readline_fn_t)(void *baton,
+ svn_stringbuf_t **stringbuf,
+ const char **eol,
+ svn_boolean_t *eof,
+ svn_boolean_t detect_eol,
+ svn_read_fn_t read_fn,
+ svn_io_mark_fn_t mark_fn,
+ svn_io_seek_fn_t seek_fn,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
/** Create a generic stream. @see svn_stream_t. */
svn_stream_t *
@@ -864,23 +863,11 @@ 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.
- */
+/** Set @a stream's readline function to @a readline_fn */
void
-svn_stream_set_line_filter_callback(svn_stream_t *stream,
- svn_io_line_filter_cb_t line_filter_cb);
+svn_stream_set_readline(svn_stream_t *stream,
+ svn_io_readline_fn_t readline_fn);
-/** Set @a streams's line-transforming callback function to
- * @a line_transformer_cb.
- *
- * @since New in 1.7.
- */
-void
-svn_stream_set_line_transformer_callback(
- svn_stream_t *stream,
- svn_io_line_transformer_cb_t line_transformer_cb);
/** Create a stream that is empty for reading and infinite for writing. */
svn_stream_t *
@@ -1203,19 +1190,6 @@ svn_stream_printf_from_utf8(svn_stream_t *stream,
*
* If @a stream runs out of bytes before encountering a line-terminator,
* then set @a *eof to @c TRUE, otherwise set @a *eof to FALSE.
- *
- * If a line-filter callback function was set on the stream using
- * svn_stream_set_line_filter_callback(), lines will only be returned
- * if they pass the filtering decision of the callback function.
- * If end-of-file is encountered while reading the line and the line
- * is filtered, @a *stringbuf will be empty.
- *
- * If a line-transformer callback function was set on the stream using
- * svn_stream_set_line_transformer_callback(), lines will be returned
- * transformed, in a way determined by the callback.
- *
- * Note that the line-transformer callback gets called after the line-filter
- * callback, not before.
*/
svn_error_t *
svn_stream_readline(svn_stream_t *stream,
@@ -1230,6 +1204,11 @@ svn_stream_readline(svn_stream_t *stream,
* is returned in @a *eol. If EOF is reached and the stream does not
* end with a newline character, @a *eol will be NULL.
*
+ * The @a stream is required to support mark and seek. @see svn_stream_mark.
+ *
+ * The @a *stringbuf will be allocated in @a result_pool.
+ * @a scratch_pool is used for temporary allocations.
+ *
* @since New in 1.7.
*/
svn_error_t *
@@ -1237,7 +1216,8 @@ svn_stream_readline_detect_eol(svn_stream_t *strea
svn_stringbuf_t **stringbuf,
const char **eol,
svn_boolean_t *eof,
- apr_pool_t *pool);
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
/**
* Read the contents of the readable stream @a from and write them to the
Index: subversion/libsvn_diff/parse-diff.c
===================================================================
--- subversion/libsvn_diff/parse-diff.c (revision 961349)
+++ subversion/libsvn_diff/parse-diff.c (working copy)
@@ -33,6 +33,8 @@
#include "svn_dirent_uri.h"
#include "svn_diff.h"
+#include "private/svn_eol_private.h"
+
/* Helper macro for readability */
#define starts_with(str, start) \
(strncmp((str), (start), strlen(start)) == 0)
@@ -184,89 +186,405 @@ parse_hunk_header(const char *header, svn_hunk_t *
return TRUE;
}
-/* A stream line-filter which allows only original text from a hunk,
- * and filters special lines (which start with a backslash). */
+/* Users of the diff parsing API are provided with various streams
+ * to read lines from a hunk. These streams return:
+ *
+ * - the original hunk text (all lines starting with '-' or ' ')
+ * - the modified hunk text (all lines starting with '+' or ' ')
+ * - the plain unidiff text (possibly reversed)
+ *
+ * To achieve this, we wrap the patch file stream with custom streams,
+ * which override the wrapped stream's readline method. */
+
+/* Baton for a stream that reads hunk texts. */
+struct hunk_text_stream_baton {
+ /* The leading unidiff symbol of lines which should be filtered.
+ * Can be '+' or '-', depending on whether we're providing the original
+ * or modified version of the hunk. */
+ char verboten;
+
+ svn_stream_t *wrapped_stream;
+};
+
+/* An implementation of svn_read_fn_t. */
static svn_error_t *
-original_line_filter(svn_boolean_t *filtered, const char *line, void *baton,
- apr_pool_t *scratch_pool)
+read_handler_hunk_text(void *baton, char *buffer, apr_size_t *len)
{
- *filtered = (line[0] == '+' || line[0] == '\\');
- return SVN_NO_ERROR;
+ struct hunk_text_stream_baton *b = baton;
+ return svn_stream_read(b->wrapped_stream, buffer, len);
}
-/* A stream line-filter which allows only modified text from a hunk,
- * and filters special lines (which start with a backslash). */
+/* An implementation of svn_write_fn_t. */
static svn_error_t *
-modified_line_filter(svn_boolean_t *filtered, const char *line, void *baton,
- apr_pool_t *scratch_pool)
+write_handler_hunk_text(void *baton, const char *buffer, apr_size_t *len)
{
- *filtered = (line[0] == '-' || line[0] == '\\');
- return SVN_NO_ERROR;
+ struct hunk_text_stream_baton *b = baton;
+ return svn_stream_write(b->wrapped_stream, buffer, len);
}
-/** line-transformer callback to shave leading diff symbols. */
+/* An implementation of svn_close_fn_t. */
static svn_error_t *
-remove_leading_char_transformer(svn_stringbuf_t **buf,
- const char *line,
- void *baton,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
+close_handler_hunk_text(void *baton)
{
- if (line[0] == '+' || line[0] == '-' || line[0] == ' ')
- *buf = svn_stringbuf_create(line + 1, result_pool);
- else
- *buf = svn_stringbuf_create(line, result_pool);
+ struct hunk_text_stream_baton *b = baton;
+ return svn_stream_close(b->wrapped_stream);
+}
+/* An implementation of svn_io_reset_fn_t. */
+static svn_error_t *
+reset_handler_hunk_text(void *baton)
+{
+ struct hunk_text_stream_baton *b = baton;
+ return svn_stream_reset(b->wrapped_stream);
+}
+
+/* An implementation of svn_io_mark_fn_t. */
+static svn_error_t *
+mark_handler_hunk_text(void *baton, svn_stream_mark_t **mark, apr_pool_t *pool)
+{
+ struct hunk_text_stream_baton *b = baton;
+ return svn_stream_mark(b->wrapped_stream, mark, pool);
+}
+
+/* An implementation of svn_io_seek_fn_t. */
+static svn_error_t *
+seek_handler_hunk_text(void *baton, svn_stream_mark_t *mark)
+{
+ struct hunk_text_stream_baton *b = baton;
+ return svn_stream_seek(b->wrapped_stream, mark);
+}
+
+/* Invoke the READ_FN function of a stream to scan for an end-of-line
+ * indicator, and return it in *EOL.
+ * Set *EOL to NULL if the stream runs out before an end-of-line indicator
+ * is found. */
+static svn_error_t *
+scan_eol(void *baton,
+ svn_read_fn_t read_fn,
+ svn_io_mark_fn_t mark_fn,
+ svn_io_seek_fn_t seek_fn,
+ const char **eol,
+ apr_pool_t *pool)
+{
+ const char *eol_str;
+ svn_stream_mark_t *mark;
+
+ SVN_ERR(mark_fn(baton, &mark, pool));
+
+ eol_str = NULL;
+ while (! eol_str)
+ {
+ char buf[512];
+ apr_size_t len;
+
+ len = sizeof(buf);
+ SVN_ERR(read_fn(baton, buf, &len));
+ if (len == 0)
+ break; /* EOF */
+ eol_str = svn_eol__detect_eol(buf, buf + len);
+ }
+
+ SVN_ERR(seek_fn(baton, mark));
+
+ *eol = eol_str;
+
return SVN_NO_ERROR;
}
-/** line-transformer callback to reverse a diff text. */
+/* An implementation of svn_io_readline_fn_t. */
static svn_error_t *
-reverse_diff_transformer(svn_stringbuf_t **buf,
- const char *line,
- void *baton,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
+readline_handler_hunk_text(void *baton,
+ svn_stringbuf_t **stringbuf,
+ const char **eol,
+ svn_boolean_t *eof,
+ svn_boolean_t detect_eol,
+ svn_read_fn_t read_fn,
+ svn_io_mark_fn_t mark_fn,
+ svn_io_seek_fn_t seek_fn,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
- svn_hunk_t hunk;
+ svn_stringbuf_t *str;
+ apr_pool_t *iterpool;
+ svn_boolean_t filtered;
+ const char *eol_str;
+ struct hunk_text_stream_baton *b = baton;
- /* ### Pass the already parsed hunk via the baton?
- * ### Maybe we should really make svn_stream_readline() a proper stream
- * ### method and override it instead of adding special callbacks? */
- if (parse_hunk_header(line, &hunk, "@@", FALSE, scratch_pool))
+ *eof = FALSE;
+
+ iterpool = svn_pool_create(scratch_pool);
+ do
{
- *buf = svn_stringbuf_createf(result_pool,
- "@@ -%lu,%lu +%lu,%lu @@",
- hunk.modified_start,
- hunk.modified_length,
- hunk.original_start,
- hunk.original_length);
+ apr_size_t numbytes;
+ const char *match;
+ char c;
+
+ svn_pool_clear(iterpool);
+
+ /* Since we're reading one character at a time, let's at least
+ optimize for the 90% case. 90% of the time, we can avoid the
+ stringbuf ever having to realloc() itself if we start it out at
+ 80 chars. */
+ str = svn_stringbuf_create_ensure(80, iterpool);
+
+ if (detect_eol)
+ {
+ SVN_ERR(scan_eol(baton, read_fn, mark_fn, seek_fn,
+ &eol_str, iterpool));
+ if (eol)
+ *eol = eol_str;
+ if (eol_str == NULL)
+ {
+ /* No newline until EOF, EOL_STR can be anything. */
+ eol_str = APR_EOL_STR;
+ }
+ }
+ else
+ eol_str = *eol;
+
+ /* Read into STR up to and including the next EOL sequence. */
+ match = eol_str;
+ numbytes = 1;
+ while (*match)
+ {
+ SVN_ERR(read_fn(baton, &c, &numbytes));
+ if (numbytes != 1)
+ {
+ /* a 'short' read means the stream has run out. */
+ *eof = TRUE;
+ /* We know we don't have a whole EOL sequence, but ensure we
+ * don't chop off any partial EOL sequence that we may have. */
+ match = eol_str;
+ /* Process this short (or empty) line just like any other
+ * except with *EOF set. */
+ break;
+ }
+
+ if (c == *match)
+ match++;
+ else
+ match = eol_str;
+
+ svn_stringbuf_appendbytes(str, &c, 1);
+ }
+
+ svn_stringbuf_chop(str, match - eol_str);
+ filtered = (str->data[0] == b->verboten || str->data[0] == '\\');
}
- else if (parse_hunk_header(line, &hunk, "##", FALSE, scratch_pool))
+ while (filtered && ! *eof);
+ /* Not destroying the iterpool just yet since we still need STR
+ * which is allocated in it. */
+
+ if (filtered)
{
- *buf = svn_stringbuf_createf(result_pool,
- "## -%lu,%lu +%lu,%lu ##",
- hunk.modified_start,
- hunk.modified_length,
- hunk.original_start,
- hunk.original_length);
+ /* EOF, return an empty string. */
+ *stringbuf = svn_stringbuf_create_ensure(0, result_pool);
}
- else if (line[0] == '+')
+ else if (str->data[0] == '+' || str->data[0] == '-' || str->data[0] == ' ')
{
- *buf = svn_stringbuf_create(line, result_pool);
- (*buf)->data[0] = '-';
+ /* Shave off leading unidiff symbols. */
+ *stringbuf = svn_stringbuf_create(str->data + 1, result_pool);
}
- else if (line[0] == '-')
+ else
{
- *buf = svn_stringbuf_create(line, result_pool);
- (*buf)->data[0] = '+';
+ /* Return the line as-is. */
+ *stringbuf = svn_stringbuf_dup(str, result_pool);
}
+
+ /* Done. RIP iterpool. */
+ svn_pool_destroy(iterpool);
+
+ return SVN_NO_ERROR;
+}
+
+/* Return a stream for reading hunk text from WRAPPED_STREAM.
+ * VERBOTEN is the leading character of lines which should be
+ * filtered by this stream's readline method ('+' or '-').
+ * Allocate the new stream in RESULT_POOL. */
+static svn_stream_t *
+stream_hunk_text(svn_stream_t *wrapped_stream,
+ char verboten,
+ apr_pool_t *result_pool)
+{
+ svn_stream_t *stream;
+ struct hunk_text_stream_baton *baton;
+
+ baton = apr_palloc(result_pool, sizeof(*baton));
+ baton->wrapped_stream = wrapped_stream;
+ baton->verboten = verboten;
+
+ stream = svn_stream_create(baton, result_pool);
+
+ svn_stream_set_read(stream, read_handler_hunk_text);
+ svn_stream_set_write(stream, write_handler_hunk_text);
+ svn_stream_set_close(stream, close_handler_hunk_text);
+ svn_stream_set_reset(stream, reset_handler_hunk_text);
+ svn_stream_set_mark(stream, mark_handler_hunk_text);
+ svn_stream_set_seek(stream, seek_handler_hunk_text);
+ svn_stream_set_readline(stream, readline_handler_hunk_text);
+
+ return stream;
+}
+
+/* Return a stream to read the original text of a hunk from
+ * WRAPPED_STREAM, and allocated in RESULT_POOL.*/
+static svn_stream_t *
+stream_hunk_text_original(svn_stream_t *wrapped_stream,
+ apr_pool_t *result_pool)
+{
+ return stream_hunk_text(wrapped_stream, '+', result_pool);
+}
+
+/* Return a stream to read the modified text of a hunk from
+ * WRAPPED_STREAM, and allocated in RESULT_POOL.*/
+static svn_stream_t *
+stream_hunk_text_modified(svn_stream_t *wrapped_stream,
+ apr_pool_t *result_pool)
+{
+ return stream_hunk_text(wrapped_stream, '-', result_pool);
+}
+
+
+/* Baton for a stream that reads unidiff text reversed. */
+struct reverse_diff_text_stream_baton {
+ svn_stream_t *wrapped_stream;
+};
+
+/* An implementation of svn_read_fn_t. */
+static svn_error_t *
+read_handler_reverse_diff_text(void *baton, char *buffer, apr_size_t *len)
+{
+ struct reverse_diff_text_stream_baton *b = baton;
+ return svn_stream_read(b->wrapped_stream, buffer, len);
+}
+
+/* An implementation of svn_write_fn_t. */
+static svn_error_t *
+write_handler_reverse_diff_text(void *baton, const char *buffer,
+ apr_size_t *len)
+{
+ struct reverse_diff_text_stream_baton *b = baton;
+ return svn_stream_write(b->wrapped_stream, buffer, len);
+}
+
+/* An implementation of svn_close_fn_t. */
+static svn_error_t *
+close_handler_reverse_diff_text(void *baton)
+{
+ struct reverse_diff_text_stream_baton *b = baton;
+ return svn_stream_close(b->wrapped_stream);
+}
+
+/* An implementation of svn_io_reset_fn_t. */
+static svn_error_t *
+reset_handler_reverse_diff_text(void *baton)
+{
+ struct reverse_diff_text_stream_baton *b = baton;
+ return svn_stream_reset(b->wrapped_stream);
+}
+
+/* An implementation of svn_io_mark_fn_t. */
+static svn_error_t *
+mark_handler_reverse_diff_text(void *baton, svn_stream_mark_t **mark,
+ apr_pool_t *pool)
+{
+ struct reverse_diff_text_stream_baton *b = baton;
+ return svn_stream_mark(b->wrapped_stream, mark, pool);
+}
+
+/* An implementation of svn_io_seek_fn_t. */
+static svn_error_t *
+seek_handler_reverse_diff_text(void *baton, svn_stream_mark_t *mark)
+{
+ struct hunk_text_stream_baton *b = baton;
+ return svn_stream_seek(b->wrapped_stream, mark);
+}
+
+/* An implementation of svn_io_readline_fn_t. */
+static svn_error_t *
+readline_handler_reverse_diff_text(void *baton,
+ svn_stringbuf_t **stringbuf,
+ const char **eol,
+ svn_boolean_t *eof,
+ svn_boolean_t detect_eol,
+ svn_read_fn_t read_fn,
+ svn_io_mark_fn_t mark_fn,
+ svn_io_seek_fn_t seek_fn,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ svn_hunk_t hunk;
+ svn_stringbuf_t *line;
+ struct reverse_diff_text_stream_baton *b = baton;
+
+ /* Read the line and perform necessary transformations to
+ * produce a reversed diff. */
+ if (detect_eol)
+ SVN_ERR(svn_stream_readline_detect_eol(b->wrapped_stream,
+ &line, eol, eof,
+ result_pool, scratch_pool));
else
- *buf = svn_stringbuf_create(line, result_pool);
+ SVN_ERR(svn_stream_readline(b->wrapped_stream, &line, *eol, eof,
+ result_pool));
+ if (parse_hunk_header(line->data, &hunk, "@@", FALSE, scratch_pool))
+ {
+ /* Line is a hunk header, reverse it. */
+ *stringbuf = svn_stringbuf_createf(result_pool,
+ "@@ -%lu,%lu +%lu,%lu @@",
+ hunk.modified_start,
+ hunk.modified_length,
+ hunk.original_start,
+ hunk.original_length);
+ }
+ else if (parse_hunk_header(line->data, &hunk, "##", FALSE, scratch_pool))
+ {
+ /* Line is a hunk header, reverse it. */
+ *stringbuf = svn_stringbuf_createf(result_pool,
+ "## -%lu,%lu +%lu,%lu ##",
+ hunk.modified_start,
+ hunk.modified_length,
+ hunk.original_start,
+ hunk.original_length);
+ }
+ else
+ {
+ if (line->data[0] == '+')
+ line->data[0] = '-';
+ else if (line->data[0] == '-')
+ line->data[0] = '+';
+
+ *stringbuf = line;
+ }
+
return SVN_NO_ERROR;
}
+/* Return a stream for reading diff text from WRAPPED_STREAM.
+ * The unidiff will appear reversed when read via the stream's readline method.
+ * Allocate the new stream in RESULT_POOL. */
+static svn_stream_t *
+stream_reverse_diff_text(svn_stream_t *wrapped_stream,
+ apr_pool_t *result_pool)
+{
+ svn_stream_t *stream;
+ struct reverse_diff_text_stream_baton *baton;
+
+ baton = apr_palloc(result_pool, sizeof(*baton));
+ baton->wrapped_stream = wrapped_stream;
+
+ stream = svn_stream_create(baton, result_pool);
+ svn_stream_set_read(stream, read_handler_reverse_diff_text);
+ svn_stream_set_write(stream, write_handler_reverse_diff_text);
+ svn_stream_set_close(stream, close_handler_reverse_diff_text);
+ svn_stream_set_reset(stream, reset_handler_reverse_diff_text);
+ svn_stream_set_mark(stream, mark_handler_reverse_diff_text);
+ svn_stream_set_seek(stream, seek_handler_reverse_diff_text);
+ svn_stream_set_readline(stream, readline_handler_reverse_diff_text);
+
+ return stream;
+}
+
/* Parse PROP_NAME from HEADER as the part after the INDICATOR line. */
static svn_error_t *
parse_prop_name(const char **prop_name, const char *header,
@@ -349,7 +667,7 @@ parse_next_hunk(svn_hunk_t **hunk,
/* Remember the current line's offset, and read the line. */
last_line = pos;
SVN_ERR(svn_stream_readline_detect_eol(stream, &line, NULL, &eof,
- iterpool));
+ iterpool, iterpool));
if (! eof)
{
@@ -502,38 +820,41 @@ parse_next_hunk(svn_hunk_t **hunk,
apr_file_t *f;
apr_int32_t flags = APR_READ | APR_BUFFERED;
+ /* For each of the streams created below, we re-open the patch file.
+ * Each stream needs its own file descriptor in order to have
+ * independent seek behaviour. */
+
/* Create a stream which returns the hunk text itself. */
SVN_ERR(svn_io_file_open(&f, patch->path, flags, APR_OS_DEFAULT,
result_pool));
diff_text = svn_stream_from_aprfile_range_readonly(f, FALSE,
start, end,
result_pool);
+ if (reverse)
+ diff_text = stream_reverse_diff_text(diff_text, result_pool);
/* Create a stream which returns the original hunk text. */
SVN_ERR(svn_io_file_open(&f, patch->path, flags, APR_OS_DEFAULT,
result_pool));
- original_text = svn_stream_from_aprfile_range_readonly(f, FALSE,
- start, end,
- result_pool);
- svn_stream_set_line_filter_callback(original_text, original_line_filter);
- svn_stream_set_line_transformer_callback(original_text,
- remove_leading_char_transformer);
+ original_text = stream_hunk_text_original(
+ svn_stream_from_aprfile_range_readonly(f, FALSE,
+ start, end,
+ result_pool),
+ result_pool);
/* Create a stream which returns the modified hunk text. */
SVN_ERR(svn_io_file_open(&f, patch->path, flags, APR_OS_DEFAULT,
result_pool));
- modified_text = svn_stream_from_aprfile_range_readonly(f, FALSE,
- start, end,
- result_pool);
- svn_stream_set_line_filter_callback(modified_text, modified_line_filter);
- svn_stream_set_line_transformer_callback(modified_text,
- remove_leading_char_transformer);
+ modified_text = stream_hunk_text_modified(
+ svn_stream_from_aprfile_range_readonly(f, FALSE,
+ start, end,
+ result_pool),
+ result_pool);
+
/* Set the hunk's texts. */
(*hunk)->diff_text = diff_text;
if (reverse)
{
- svn_stream_set_line_transformer_callback(diff_text,
- reverse_diff_transformer);
(*hunk)->original_text = modified_text;
(*hunk)->modified_text = original_text;
}
@@ -918,7 +1239,7 @@ svn_diff_parse_next_patch(svn_patch_t **patch,
/* Remember the current line's offset, and read the line. */
last_line = pos;
SVN_ERR(svn_stream_readline_detect_eol(stream, &line, NULL, &eof,
- iterpool));
+ iterpool, iterpool));
if (! eof)
{
Index: subversion/libsvn_subr/stream.c
===================================================================
--- subversion/libsvn_subr/stream.c (revision 961349)
+++ subversion/libsvn_subr/stream.c (working copy)
@@ -53,8 +53,7 @@ struct svn_stream_t {
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;
+ svn_io_readline_fn_t readline_fn;
};
@@ -73,8 +72,7 @@ svn_stream_create(void *baton, apr_pool_t *pool)
stream->reset_fn = NULL;
stream->mark_fn = NULL;
stream->seek_fn = NULL;
- stream->line_filter_cb = NULL;
- stream->line_transformer_cb = NULL;
+ stream->readline_fn = NULL;
return stream;
}
@@ -124,20 +122,11 @@ svn_stream_set_seek(svn_stream_t *stream, svn_io_s
}
void
-svn_stream_set_line_filter_callback(svn_stream_t *stream,
- svn_io_line_filter_cb_t line_filter_cb)
+svn_stream_set_readline(svn_stream_t *stream, svn_io_readline_fn_t readline_fn)
{
- stream->line_filter_cb = line_filter_cb;
+ stream->readline_fn = readline_fn;
}
-void
-svn_stream_set_line_transformer_callback(
- svn_stream_t *stream,
- svn_io_line_transformer_cb_t line_transformer_cb)
-{
- stream->line_transformer_cb = line_transformer_cb;
-}
-
svn_error_t *
svn_stream_read(svn_stream_t *stream, char *buffer, apr_size_t *len)
{
@@ -233,55 +222,23 @@ svn_stream_printf_from_utf8(svn_stream_t *stream,
return svn_stream_write(stream, translated, &len);
}
-/* If a line filter callback was set on STREAM, invoke it on LINE,
- * and indicate in *FILTERED whether the line should be filtered.
- * If no line filter callback was set on STREAM, just set *FILTERED to FALSE.
- */
-static svn_error_t *
-line_filter(svn_stream_t *stream, svn_boolean_t *filtered, const char *line,
- apr_pool_t *pool)
-{
- apr_pool_t *scratch_pool;
-
- if (! stream->line_filter_cb)
- {
- *filtered = FALSE;
- return SVN_NO_ERROR;
- }
-
- scratch_pool = svn_pool_create(pool);
- SVN_ERR(stream->line_filter_cb(filtered, line, stream->baton, scratch_pool));
- svn_pool_destroy(scratch_pool);
- return SVN_NO_ERROR;
-}
-
-/* Run the line transformer callback of STREAM with LINE as input,
- * and expect the transformation result to be returned in BUF,
- * allocated in POOL. */
-static svn_error_t *
-line_transformer(svn_stream_t *stream, svn_stringbuf_t **buf,
- const char *line, apr_pool_t *pool, apr_pool_t *scratch_pool)
-{
- *buf = NULL; /* so we can assert that the callback has set it non-null */
- SVN_ERR(stream->line_transformer_cb(buf, line, stream->baton,
- pool, scratch_pool));
-
- /* Die if the line transformer didn't provide any output. */
- SVN_ERR_ASSERT(*buf);
-
- return SVN_NO_ERROR;
-}
-
-/* Scan STREAM for an end-of-line indicatior, and return it in *EOL.
+/* Invoke the READ_FN function of a stream to scan for an end-of-line
+ * indicatior, and return it in *EOL.
+ * Use MARK_FN and SEEK_FN to seek in the stream.
* 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, apr_pool_t *pool)
+scan_eol(void *baton,
+ svn_read_fn_t read_fn,
+ svn_io_mark_fn_t mark_fn,
+ svn_io_seek_fn_t seek_fn,
+ const char **eol,
+ apr_pool_t *pool)
{
const char *eol_str;
svn_stream_mark_t *mark;
- SVN_ERR(svn_stream_mark(stream, &mark, pool));
+ SVN_ERR(mark_fn(baton, &mark, pool));
eol_str = NULL;
while (! eol_str)
@@ -290,113 +247,82 @@ static svn_error_t *
apr_size_t len;
len = sizeof(buf);
- SVN_ERR(svn_stream_read(stream, buf, &len));
+ SVN_ERR(read_fn(baton, buf, &len));
if (len == 0)
break; /* EOF */
eol_str = svn_eol__detect_eol(buf, buf + len);
}
- SVN_ERR(svn_stream_seek(stream, mark));
+ SVN_ERR(seek_fn(baton, mark));
*eol = eol_str;
return SVN_NO_ERROR;
}
-/* Guts of svn_stream_readline() and svn_stream_readline_detect_eol().
- * Returns the line read from STREAM in *STRINGBUF, and indicates
- * end-of-file in *EOF. If DETECT_EOL is TRUE, the end-of-line indicator
- * is detected automatically and returned in *EOL.
- * If DETECT_EOL is FALSE, *EOL must point to the desired end-of-line
- * indicator. STRINGBUF is allocated in POOL. */
+/* An implementation of svn_io_readline_fn_t */
static svn_error_t *
-stream_readline(svn_stringbuf_t **stringbuf,
- svn_boolean_t *eof,
+stream_readline(void *baton,
+ svn_stringbuf_t **stringbuf,
const char **eol,
- svn_stream_t *stream,
+ svn_boolean_t *eof,
svn_boolean_t detect_eol,
- apr_pool_t *pool)
+ svn_read_fn_t read_fn,
+ svn_io_mark_fn_t mark_fn,
+ svn_io_seek_fn_t seek_fn,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
- svn_stringbuf_t *str;
- apr_pool_t *iterpool;
- svn_boolean_t filtered;
+ apr_size_t numbytes;
+ const char *match;
+ char c;
const char *eol_str;
+ /* Since we're reading one character at a time, let's at least
+ optimize for the 90% case. 90% of the time, we can avoid the
+ stringbuf ever having to realloc() itself if we start it out at
+ 80 chars. */
+ svn_stringbuf_t *str = svn_stringbuf_create_ensure(80, scratch_pool);
- *eof = FALSE;
-
- iterpool = svn_pool_create(pool);
- do
+ if (detect_eol)
{
- apr_size_t numbytes;
- const char *match;
- char c;
-
- svn_pool_clear(iterpool);
-
- /* Since we're reading one character at a time, let's at least
- optimize for the 90% case. 90% of the time, we can avoid the
- stringbuf ever having to realloc() itself if we start it out at
- 80 chars. */
- str = svn_stringbuf_create_ensure(80, iterpool);
-
- if (detect_eol)
+ SVN_ERR(scan_eol(baton, read_fn, mark_fn, seek_fn,
+ &eol_str, scratch_pool));
+ if (eol)
+ *eol = eol_str;
+ if (eol_str == NULL)
{
- SVN_ERR(scan_eol(&eol_str, stream, iterpool));
- if (eol)
- *eol = eol_str;
- if (! eol_str)
- {
- /* No newline until EOF, EOL_STR can be anything. */
- eol_str = APR_EOL_STR;
- }
+ /* No newline until EOF, EOL_STR can be anything. */
+ eol_str = APR_EOL_STR;
}
- else
- eol_str = *eol;
+ }
+ else
+ eol_str = *eol;
- /* Read into STR up to and including the next EOL sequence. */
- match = eol_str;
+ /* Read into STR up to and including the next EOL sequence. */
+ match = eol_str;
+ while (*match)
+ {
numbytes = 1;
- while (*match)
+ SVN_ERR(read_fn(baton, &c, &numbytes));
+ if (numbytes != 1)
{
- SVN_ERR(svn_stream_read(stream, &c, &numbytes));
- if (numbytes != 1)
- {
- /* a 'short' read means the stream has run out. */
- *eof = TRUE;
- /* We know we don't have a whole EOL sequence, but ensure we
- * don't chop off any partial EOL sequence that we may have. */
- match = eol_str;
- /* Process this short (or empty) line just like any other
- * except with *EOF set. */
- break;
- }
-
- if (c == *match)
- match++;
- else
- match = eol_str;
-
- svn_stringbuf_appendbytes(str, &c, 1);
+ /* a 'short' read means the stream has run out. */
+ *eof = TRUE;
+ *stringbuf = svn_stringbuf_dup(str, result_pool);
+ return SVN_NO_ERROR;
}
- svn_stringbuf_chop(str, match - eol_str);
+ if (c == *match)
+ match++;
+ else
+ match = eol_str;
- SVN_ERR(line_filter(stream, &filtered, str->data, iterpool));
+ svn_stringbuf_appendbytes(str, &c, 1);
}
- while (filtered && ! *eof);
- /* Not destroying the iterpool just yet since we still need STR
- * which is allocated in it. */
- if (filtered)
- *stringbuf = svn_stringbuf_create_ensure(0, pool);
- else if (stream->line_transformer_cb)
- SVN_ERR(line_transformer(stream, stringbuf, str->data, pool, iterpool));
- else
- *stringbuf = svn_stringbuf_dup(str, pool);
-
- /* Done. RIP iterpool. */
- svn_pool_destroy(iterpool);
-
+ *eof = FALSE;
+ svn_stringbuf_chop(str, match - eol_str);
+ *stringbuf = svn_stringbuf_dup(str, result_pool);
return SVN_NO_ERROR;
}
@@ -407,8 +333,23 @@ svn_stream_readline(svn_stream_t *stream,
svn_boolean_t *eof,
apr_pool_t *pool)
{
- return svn_error_return(stream_readline(stringbuf, eof, &eol, stream,
- FALSE, pool));
+ svn_io_readline_fn_t readline_fn;
+
+ /* Provide a default readline implementation if the stream
+ * hasn't overridden it. This is needed for backwards compat
+ * to 1.6.x and earlier. */
+ if (stream->readline_fn)
+ readline_fn = stream->readline_fn;
+ else
+ readline_fn = stream_readline;
+
+ return svn_error_return(readline_fn(stream->baton,
+ stringbuf, &eol, eof,
+ FALSE,
+ stream->read_fn,
+ stream->mark_fn,
+ stream->seek_fn,
+ pool, pool));
}
svn_error_t *
@@ -416,13 +357,36 @@ svn_stream_readline_detect_eol(svn_stream_t *strea
svn_stringbuf_t **stringbuf,
const char **eol,
svn_boolean_t *eof,
- apr_pool_t *pool)
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
- return svn_error_return(stream_readline(stringbuf, eof, eol, stream,
- TRUE, pool));
-}
+ svn_io_readline_fn_t readline_fn;
+ /* Provide a default readline implementation if the stream
+ * hasn't overridden it. This is not needed for backwards compat
+ * to 1.6.x and earlier (this function is new in 1.7), but it
+ * is nice anyway because it saves us from adding dummy readline
+ * methods to custom streams sprinkled throughout the code. */
+ if (stream->readline_fn)
+ readline_fn = stream->readline_fn;
+ else
+ readline_fn = stream_readline;
+ /* EOL-detection requires mark/seek support. */
+ if (stream->mark_fn == NULL)
+ return svn_error_create(SVN_ERR_STREAM_SEEK_NOT_SUPPORTED, NULL, NULL);
+ if (stream->seek_fn == NULL)
+ return svn_error_create(SVN_ERR_STREAM_SEEK_NOT_SUPPORTED, NULL, NULL);
+
+ return svn_error_return(readline_fn(stream->baton,
+ stringbuf, eol, eof,
+ TRUE,
+ stream->read_fn,
+ stream->mark_fn,
+ stream->seek_fn,
+ result_pool, scratch_pool));
+}
+
svn_error_t *svn_stream_copy3(svn_stream_t *from, svn_stream_t *to,
svn_cancel_func_t cancel_func,
void *cancel_baton,
@@ -536,7 +500,27 @@ seek_handler_empty(void *baton, svn_stream_mark_t
return SVN_NO_ERROR;
}
+static svn_error_t *
+readline_handler_empty(void *baton,
+ svn_read_fn_t read_fn,
+ svn_io_mark_fn_t mark_fn,
+ svn_io_seek_fn_t seek_fn,
+ svn_stringbuf_t **stringbuf,
+ const char **eol,
+ svn_boolean_t *eof,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ *stringbuf = svn_stringbuf_create_ensure(0, result_pool);
+ if (eol && *eol == NULL)
+ *eol = APR_EOL_STR;
+
+ *eof = TRUE;
+
+ return SVN_NO_ERROR;
+}
+
svn_stream_t *
svn_stream_empty(apr_pool_t *pool)
{
@@ -548,6 +532,8 @@ svn_stream_empty(apr_pool_t *pool)
svn_stream_set_reset(stream, reset_handler_empty);
svn_stream_set_mark(stream, mark_handler_empty);
svn_stream_set_seek(stream, seek_handler_empty);
+ svn_stream_set_readline(stream, readline_handler_empty);
+
return stream;
}
@@ -652,6 +638,7 @@ svn_stream_disown(svn_stream_t *stream, apr_pool_t
svn_stream_set_reset(s, reset_handler_disown);
svn_stream_set_mark(s, mark_handler_disown);
svn_stream_set_seek(s, seek_handler_disown);
+ svn_stream_set_readline(s, stream_readline);
return s;
}
@@ -820,6 +807,7 @@ svn_stream_from_aprfile2(apr_file_t *file,
svn_stream_set_reset(stream, reset_handler_apr);
svn_stream_set_mark(stream, mark_handler_apr);
svn_stream_set_seek(stream, seek_handler_apr);
+ svn_stream_set_readline(stream, stream_readline);
if (! disown)
svn_stream_set_close(stream, close_handler_apr);
@@ -898,6 +886,7 @@ svn_stream_from_aprfile_range_readonly(apr_file_t
svn_stream_set_reset(stream, reset_handler_apr);
svn_stream_set_mark(stream, mark_handler_apr);
svn_stream_set_seek(stream, seek_handler_apr);
+ svn_stream_set_readline(stream, stream_readline);
if (! disown)
svn_stream_set_close(stream, close_handler_apr);
@@ -1187,6 +1176,7 @@ svn_stream_compressed(svn_stream_t *stream, apr_po
svn_stream_set_read(zstream, read_handler_gz);
svn_stream_set_write(zstream, write_handler_gz);
svn_stream_set_close(zstream, close_handler_gz);
+ svn_stream_set_readline(zstream, stream_readline);
return zstream;
}
@@ -1302,6 +1292,8 @@ svn_stream_checksummed2(svn_stream_t *stream,
svn_stream_set_read(s, read_handler_checksum);
svn_stream_set_write(s, write_handler_checksum);
svn_stream_set_close(s, close_handler_checksum);
+ svn_stream_set_readline(s, stream_readline);
+
return s;
}
@@ -1384,6 +1376,8 @@ svn_stream_checksummed(svn_stream_t *stream,
svn_stream_set_read(s, read_handler_md5);
svn_stream_set_write(s, write_handler_md5);
svn_stream_set_close(s, close_handler_md5);
+ svn_stream_set_readline(s, stream_readline);
+
return s;
}
@@ -1475,6 +1469,8 @@ svn_stream_from_stringbuf(svn_stringbuf_t *str,
svn_stream_set_reset(stream, reset_handler_stringbuf);
svn_stream_set_mark(stream, mark_handler_stringbuf);
svn_stream_set_seek(stream, seek_handler_stringbuf);
+ svn_stream_set_readline(stream, stream_readline);
+
return stream;
}
@@ -1511,6 +1507,8 @@ svn_stream_from_string(const svn_string_t *str,
baton->amt_read = 0;
stream = svn_stream_create(baton, pool);
svn_stream_set_read(stream, read_handler_string);
+ svn_stream_set_readline(stream, stream_readline);
+
return stream;
}
Index: subversion/libsvn_client/patch.c
===================================================================
--- subversion/libsvn_client/patch.c (revision 961349)
+++ subversion/libsvn_client/patch.c (working copy)
@@ -532,7 +532,7 @@ read_line(patch_target_t *target,
SVN_ERR(svn_stream_readline_detect_eol(target->stream, &line_raw,
&eol_str, &target->eof,
- scratch_pool));
+ scratch_pool, scratch_pool));
if (target->eol_style == svn_subst_eol_style_none)
target->eol_str = eol_str;
@@ -632,7 +632,8 @@ match_hunk(svn_boolean_t *matched, patch_target_t
SVN_ERR(svn_stream_readline_detect_eol(hunk->original_text,
&hunk_line, NULL,
- &hunk_eof, iterpool));
+ &hunk_eof,
+ iterpool, iterpool));
/* Contract keywords, if any, before matching. */
SVN_ERR(svn_subst_translate_cstring2(hunk_line->data,
&hunk_line_translated,
@@ -676,7 +677,8 @@ match_hunk(svn_boolean_t *matched, patch_target_t
/* If the target has no newline at end-of-file, we get an EOF
* indication for the target earlier than we do get it for the hunk. */
SVN_ERR(svn_stream_readline_detect_eol(hunk->original_text, &hunk_line,
- NULL, &hunk_eof, iterpool));
+ NULL, &hunk_eof,
+ iterpool, iterpool));
if (hunk_line->len == 0 && hunk_eof)
*matched = lines_matched;
else
@@ -928,7 +930,8 @@ reject_hunk(patch_target_t *target, hunk_info_t *h
svn_pool_clear(iterpool);
SVN_ERR(svn_stream_readline_detect_eol(hi->hunk->diff_text, &hunk_line,
- &eol_str, &eof, iterpool));
+ &eol_str, &eof, iterpool,
+ iterpool));
if (! eof)
{
if (hunk_line->len >= 1)
@@ -994,7 +997,7 @@ apply_hunk(patch_target_t *target, hunk_info_t *hi
SVN_ERR(svn_stream_readline_detect_eol(hi->hunk->modified_text,
&hunk_line, &eol_str,
- &eof, iterpool));
+ &eof, iterpool, iterpool));
lines_read++;
if (! eof && lines_read > hi->fuzz &&
lines_read <= hi->hunk->modified_length - hi->fuzz)
Index: subversion/tests/libsvn_subr/stream-test.c
===================================================================
--- subversion/tests/libsvn_subr/stream-test.c (revision 961349)
+++ subversion/tests/libsvn_subr/stream-test.c (working copy)
@@ -307,143 +307,7 @@ test_stream_range(apr_pool_t *pool)
return SVN_NO_ERROR;
}
-/* An implementation of svn_io_line_filter_cb_t */
static svn_error_t *
-line_filter(svn_boolean_t *filtered, const char *line, void *baton,
- apr_pool_t *scratch_pool)
-{
- *filtered = strchr(line, '!') != NULL;
- return SVN_NO_ERROR;
-}
-
-static svn_error_t *
-test_stream_line_filter(apr_pool_t *pool)
-{
- static const char *lines[4] = {"Not filtered.", "Filtered!",
- "Not filtered either.", "End of the lines!"};
- svn_string_t *string;
- svn_stream_t *stream;
- svn_stringbuf_t *line;
- svn_boolean_t eof;
-
- string = svn_string_createf(pool, "%s\n%s\n%s\n%s", lines[0], lines[1],
- lines[2], lines[3]);
- stream = svn_stream_from_string(string, pool);
-
- svn_stream_set_line_filter_callback(stream, line_filter);
-
- svn_stream_readline(stream, &line, "\n", &eof, pool);
- SVN_TEST_STRING_ASSERT(line->data, lines[0]);
- /* line[1] should be filtered */
- svn_stream_readline(stream, &line, "\n", &eof, pool);
- SVN_TEST_STRING_ASSERT(line->data, lines[2]);
-
- /* The last line should also be filtered, and the resulting
- * stringbuf should be empty. */
- svn_stream_readline(stream, &line, "\n", &eof, pool);
- SVN_TEST_ASSERT(eof && svn_stringbuf_isempty(line));
-
- return SVN_NO_ERROR;
-}
-
-/* An implementation of svn_io_line_transformer_cb_t */
-static svn_error_t *
-line_transformer(svn_stringbuf_t **buf, const char *line, void *baton,
- apr_pool_t *result_pool, apr_pool_t *scratch_pool)
-{
- int i, len = strlen(line);
- char *temp = apr_palloc(scratch_pool, len + 1 );
-
- for (i = 0; i < len; i++)
- {
- temp[i] = line[len - 1 - i];
- }
-
- temp[len] = '\0';
-
- *buf = svn_stringbuf_create(temp, result_pool);
-
- return SVN_NO_ERROR;
-}
-
-static svn_error_t *
-test_stream_line_transformer(apr_pool_t *pool)
-{
- static const char *lines[4] = {"gamma", "",
- "iota", "!"};
-
- static const char *inv_lines[4] = {"ammag", "",
- "atoi", "!"};
- svn_string_t *string;
- svn_stream_t *stream;
- svn_stringbuf_t *line;
- svn_boolean_t eof;
-
- string = svn_string_createf(pool, "%s\n%s\n%s\n%s", lines[0], lines[1],
- lines[2], lines[3]);
-
- stream = svn_stream_from_string(string, pool);
-
- svn_stream_set_line_transformer_callback(stream, line_transformer);
-
- svn_stream_readline(stream, &line, "\n", &eof, pool);
- SVN_TEST_STRING_ASSERT(line->data, inv_lines[0]);
-
- svn_stream_readline(stream, &line, "\n", &eof, pool);
- SVN_TEST_STRING_ASSERT(line->data, inv_lines[1]);
-
- svn_stream_readline(stream, &line, "\n", &eof, pool);
- SVN_TEST_STRING_ASSERT(line->data, inv_lines[2]);
-
- svn_stream_readline(stream, &line, "\n", &eof, pool);
- SVN_TEST_STRING_ASSERT(line->data, inv_lines[3]);
-
- /* We should have reached eof and the stringbuf should be emtpy. */
- svn_stream_readline(stream, &line, "\n", &eof, pool);
- SVN_TEST_ASSERT(eof && svn_stringbuf_isempty(line));
-
- return SVN_NO_ERROR;
-}
-
-static svn_error_t *
-test_stream_line_filter_and_transformer(apr_pool_t *pool)
-{
- static const char *lines[4] = {"!gamma", "",
- "iota", "!"};
-
- static const char *inv_lines[4] = {"ammag", "",
- "atoi", "!"};
- svn_string_t *string;
- svn_stream_t *stream;
- svn_stringbuf_t *line;
- svn_boolean_t eof;
-
- string = svn_string_createf(pool, "%s\n%s\n%s\n%s", lines[0], lines[1],
- lines[2], lines[3]);
-
- stream = svn_stream_from_string(string, pool);
-
- svn_stream_set_line_filter_callback(stream, line_filter);
-
- svn_stream_set_line_transformer_callback(stream, line_transformer);
-
- /* Line one should be filtered. */
- svn_stream_readline(stream, &line, "\n", &eof, pool);
- SVN_TEST_STRING_ASSERT(line->data, inv_lines[1]);
-
- svn_stream_readline(stream, &line, "\n", &eof, pool);
- SVN_TEST_STRING_ASSERT(line->data, inv_lines[2]);
-
- /* The last line should also be filtered, and the resulting
- * stringbuf should be empty. */
- svn_stream_readline(stream, &line, "\n", &eof, pool);
- SVN_TEST_ASSERT(eof && svn_stringbuf_isempty(line));
-
- return SVN_NO_ERROR;
-
-}
-
-static svn_error_t *
test_stream_tee(apr_pool_t *pool)
{
svn_stringbuf_t *test_bytes = generate_test_bytes(100, pool);
@@ -647,12 +511,6 @@ struct svn_test_descriptor_t test_funcs[] =
"test compressed streams"),
SVN_TEST_PASS2(test_stream_range,
"test streams reading from range of file"),
- SVN_TEST_PASS2(test_stream_line_filter,
- "test stream line filtering"),
- SVN_TEST_PASS2(test_stream_line_transformer,
- "test stream line transforming"),
- SVN_TEST_PASS2(test_stream_line_filter_and_transformer,
- "test stream line filtering and transforming"),
SVN_TEST_PASS2(test_stream_tee,
"test 'tee' streams"),
SVN_TEST_PASS2(test_stream_seek_file,
Received on 2010-07-08 13:39:53 CEST