stream filter: add "no more input" to the filters

Some filters may need to buffer the input and look-ahead inside it to decide what to output, and they may consume more than zero bytes of input and still not produce any output. After feeding all the input, pass NULL as input as keep calling stream_filter() to let such filters know there is no more input coming, and it is time for them to produce the remaining output based on the buffered input. Signed-off-by: Junio C Hamano <gitster@pobox.com>

Junio C Hamano committed May 21, 2011 at 14:05 UTC 4ae6670444388f5ba68850e42a93af4019922c26
3 files changed +35 -4
convert.c
+5 -1
@@ -838,7 +838,11 @@ static int null_filter_fn(struct stream_filter *filter,
838 const char *input, size_t *isize_p,
839 char *output, size_t *osize_p)
840 {
841 - size_t count = *isize_p;
841 + size_t count;
842 +
843 + if (!input)
844 + return 0; /* we do not keep any states */
845 + count = *isize_p;
846 if (*osize_p < count)
847 count = *osize_p;
848 if (count) {
convert.h
+7
@@ -57,6 +57,13 @@ extern int is_null_stream_filter(struct stream_filter *);
57 * Use as much input up to *isize_p and fill output up to *osize_p;
58 * update isize_p and osize_p to indicate how much buffer space was
59 * consumed and filled. Return 0 on success, non-zero on error.
60 + *
61 + * Some filters may need to buffer the input and look-ahead inside it
62 + * to decide what to output, and they may consume more than zero bytes
63 + * of input and still not produce any output. After feeding all the
64 + * input, pass NULL as input and keep calling this function, to let
65 + * such filters know there is no more input coming and it is time for
66 + * them to produce the remaining output based on the buffered input.
67 */
68 extern int stream_filter(struct stream_filter *,
69 const char *input, size_t *isize_p,
streaming.c
+23 -3
@@ -60,6 +60,7 @@ struct filtered_istream {
60 char obuf[FILTER_BUFFER];
61 int i_end, i_ptr;
62 int o_end, o_ptr;
63 + int input_finished;
64 };
65
66 struct git_istream {
@@ -215,12 +216,30 @@ static read_method_decl(filtered)
216 fs->o_end = FILTER_BUFFER - to_receive;
217 continue;
218 }
219 +
220 + /* tell the filter to drain upon no more input */
221 + if (fs->input_finished) {
222 + size_t to_receive = FILTER_BUFFER;
223 + if (stream_filter(fs->filter,
224 + NULL, NULL,
225 + fs->obuf, &to_receive))
226 + return -1;
227 + fs->o_end = FILTER_BUFFER - to_receive;
228 + if (!fs->o_end)
229 + break;
230 + continue;
231 + }
232 fs->i_end = fs->i_ptr = 0;
233
234 /* refill the input from the upstream */
221 - fs->i_end = read_istream(fs->upstream, fs->ibuf, FILTER_BUFFER);
222 - if (fs->i_end <= 0)
223 - break;
235 + if (!fs->input_finished) {
236 + fs->i_end = read_istream(fs->upstream, fs->ibuf, FILTER_BUFFER);
237 + if (fs->i_end < 0)
238 + break;
239 + if (fs->i_end)
240 + continue;
241 + }
242 + fs->input_finished = 1;
243 }
244 return filled;
245 }
@@ -241,6 +260,7 @@ static struct git_istream *attach_stream_filter(struct git_istream *st,
260 fs->filter = filter;
261 fs->i_end = fs->i_ptr = 0;
262 fs->o_end = fs->o_ptr = 0;
263 + fs->input_finished = 0;
264 ifs->size = -1; /* unknown */
265 return ifs;
266 }