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,