streaming: filter cascading
This implements an internal "cascade" filter mechanism that plugs two filters in series. Signed-off-by: Junio C Hamano <gitster@pobox.com>
Junio C Hamano committed
May 21, 2011 at 18:28 UTC
a265a7f95e6e3ebd81df0c6813b17d61a5ab890a
1 file changed
+112
-14
convert.c
+112
-14
@@ -914,6 +914,112 @@ static struct stream_filter lf_to_crlf_filter_singleton = {
914
};
915
916
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
+
1023
/*
1024
* ident filter
1025
*/
@@ -1083,20 +1189,12 @@ struct stream_filter *get_stream_filter(const char *path, const unsigned char *s
1189
crlf_action = input_crlf_action(ca.crlf_action, ca.eol_attr);
1190
1191
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);
1198
1199
return filter;
1200
}