Skip to content

Commit a265a7f

Browse files
committed
streaming: filter cascading
This implements an internal "cascade" filter mechanism that plugs two filters in series. Signed-off-by: Junio C Hamano <[email protected]>
1 parent b84c783 commit a265a7f

File tree

1 file changed

+112
-14
lines changed

1 file changed

+112
-14
lines changed

convert.c

Lines changed: 112 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -914,6 +914,112 @@ static struct stream_filter lf_to_crlf_filter_singleton = {
914914
};
915915

916916

917+
/*
918+
* Cascade filter
919+
*/
920+
#define FILTER_BUFFER 1024
921+
struct cascade_filter {
922+
struct stream_filter filter;
923+
struct stream_filter *one;
924+
struct stream_filter *two;
925+
char buf[FILTER_BUFFER];
926+
int end, ptr;
927+
};
928+
929+
static int cascade_filter_fn(struct stream_filter *filter,
930+
const char *input, size_t *isize_p,
931+
char *output, size_t *osize_p)
932+
{
933+
struct cascade_filter *cas = (struct cascade_filter *) filter;
934+
size_t filled = 0;
935+
size_t sz = *osize_p;
936+
size_t to_feed, remaining;
937+
938+
/*
939+
* input -- (one) --> buf -- (two) --> output
940+
*/
941+
while (filled < sz) {
942+
remaining = sz - filled;
943+
944+
/* do we already have something to feed two with? */
945+
if (cas->ptr < cas->end) {
946+
to_feed = cas->end - cas->ptr;
947+
if (stream_filter(cas->two,
948+
cas->buf + cas->ptr, &to_feed,
949+
output + filled, &remaining))
950+
return -1;
951+
cas->ptr += (cas->end - cas->ptr) - to_feed;
952+
filled = sz - remaining;
953+
continue;
954+
}
955+
956+
/* feed one from upstream and have it emit into our buffer */
957+
to_feed = input ? *isize_p : 0;
958+
if (input && !to_feed)
959+
break;
960+
remaining = sizeof(cas->buf);
961+
if (stream_filter(cas->one,
962+
input, &to_feed,
963+
cas->buf, &remaining))
964+
return -1;
965+
cas->end = sizeof(cas->buf) - remaining;
966+
cas->ptr = 0;
967+
if (input) {
968+
size_t fed = *isize_p - to_feed;
969+
*isize_p -= fed;
970+
input += fed;
971+
}
972+
973+
/* do we know that we drained one completely? */
974+
if (input || cas->end)
975+
continue;
976+
977+
/* tell two to drain; we have nothing more to give it */
978+
to_feed = 0;
979+
remaining = sz - filled;
980+
if (stream_filter(cas->two,
981+
NULL, &to_feed,
982+
output + filled, &remaining))
983+
return -1;
984+
if (remaining == (sz - filled))
985+
break; /* completely drained two */
986+
filled = sz - remaining;
987+
}
988+
*osize_p -= filled;
989+
return 0;
990+
}
991+
992+
static void cascade_free_fn(struct stream_filter *filter)
993+
{
994+
struct cascade_filter *cas = (struct cascade_filter *)filter;
995+
free_stream_filter(cas->one);
996+
free_stream_filter(cas->two);
997+
free(filter);
998+
}
999+
1000+
static struct stream_filter_vtbl cascade_vtbl = {
1001+
cascade_filter_fn,
1002+
cascade_free_fn,
1003+
};
1004+
1005+
static struct stream_filter *cascade_filter(struct stream_filter *one,
1006+
struct stream_filter *two)
1007+
{
1008+
struct cascade_filter *cascade;
1009+
1010+
if (!one || is_null_stream_filter(one))
1011+
return two;
1012+
if (!two || is_null_stream_filter(two))
1013+
return one;
1014+
1015+
cascade = xmalloc(sizeof(*cascade));
1016+
cascade->one = one;
1017+
cascade->two = two;
1018+
cascade->end = cascade->ptr = 0;
1019+
cascade->filter.vtbl = &cascade_vtbl;
1020+
return (struct stream_filter *)cascade;
1021+
}
1022+
9171023
/*
9181024
* ident filter
9191025
*/
@@ -1083,20 +1189,12 @@ struct stream_filter *get_stream_filter(const char *path, const unsigned char *s
10831189
crlf_action = input_crlf_action(ca.crlf_action, ca.eol_attr);
10841190

10851191
if ((crlf_action == CRLF_BINARY) || (crlf_action == CRLF_INPUT) ||
1086-
(crlf_action == CRLF_GUESS && auto_crlf == AUTO_CRLF_FALSE)) {
1087-
if (filter) {
1088-
free_stream_filter(filter);
1089-
return NULL;
1090-
}
1091-
return &null_filter_singleton;
1092-
} else if (output_eol(crlf_action) == EOL_CRLF &&
1093-
!(crlf_action == CRLF_AUTO || crlf_action == CRLF_GUESS)) {
1094-
if (filter) {
1095-
free_stream_filter(filter);
1096-
return NULL;
1097-
}
1098-
return &lf_to_crlf_filter_singleton;
1099-
}
1192+
(crlf_action == CRLF_GUESS && auto_crlf == AUTO_CRLF_FALSE))
1193+
filter = cascade_filter(filter, &null_filter_singleton);
1194+
1195+
else if (output_eol(crlf_action) == EOL_CRLF &&
1196+
!(crlf_action == CRLF_AUTO || crlf_action == CRLF_GUESS))
1197+
filter = cascade_filter(filter, &lf_to_crlf_filter_singleton);
11001198

11011199
return filter;
11021200
}

0 commit comments

Comments
 (0)