Skip to content

Commit 8496f56

Browse files
committed
lf_to_crlf_filter(): resurrect CRLF->CRLF hack
The non-streaming version of the filter counts CRLF and LF in the whole buffer, and returns without doing anything when they match (i.e. what is recorded in the object store already uses CRLF). This was done to help people who added files from the DOS world before realizing they want to go cross platform and adding .gitattributes to tell Git that they only want CRLF in their working tree. The streaming version of the filter does not want to read the whole thing before starting to work, as that defeats the whole point of streaming. So we instead check what byte follows CR whenever we see one, and add CR before LF only when the LF does not immediately follow CR already to keep CRLF as is. Reported-and-tested-by: Ralf Thielow Signed-off-by: Junio C Hamano <[email protected]>
1 parent 87afe9a commit 8496f56

File tree

1 file changed

+50
-10
lines changed

1 file changed

+50
-10
lines changed

convert.c

Lines changed: 50 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -879,7 +879,8 @@ int is_null_stream_filter(struct stream_filter *filter)
879879

880880
struct lf_to_crlf_filter {
881881
struct stream_filter filter;
882-
unsigned want_lf:1;
882+
unsigned has_held:1;
883+
char held;
883884
};
884885

885886
static int lf_to_crlf_filter_fn(struct stream_filter *filter,
@@ -889,10 +890,14 @@ static int lf_to_crlf_filter_fn(struct stream_filter *filter,
889890
size_t count, o = 0;
890891
struct lf_to_crlf_filter *lf_to_crlf = (struct lf_to_crlf_filter *)filter;
891892

892-
/* Output a pending LF if we need to */
893-
if (lf_to_crlf->want_lf) {
894-
output[o++] = '\n';
895-
lf_to_crlf->want_lf = 0;
893+
/*
894+
* We may be holding onto the CR to see if it is followed by a
895+
* LF, in which case we would need to go to the main loop.
896+
* Otherwise, just emit it to the output stream.
897+
*/
898+
if (lf_to_crlf->has_held && (lf_to_crlf->held != '\r' || !input)) {
899+
output[o++] = lf_to_crlf->held;
900+
lf_to_crlf->has_held = 0;
896901
}
897902

898903
/* We are told to drain */
@@ -902,22 +907,57 @@ static int lf_to_crlf_filter_fn(struct stream_filter *filter,
902907
}
903908

904909
count = *isize_p;
905-
if (count) {
910+
if (count || lf_to_crlf->has_held) {
906911
size_t i;
912+
int was_cr = 0;
913+
914+
if (lf_to_crlf->has_held) {
915+
was_cr = 1;
916+
lf_to_crlf->has_held = 0;
917+
}
918+
907919
for (i = 0; o < *osize_p && i < count; i++) {
908920
char ch = input[i];
921+
909922
if (ch == '\n') {
910923
output[o++] = '\r';
911-
if (o >= *osize_p) {
912-
lf_to_crlf->want_lf = 1;
913-
continue; /* We need to increase i */
914-
}
924+
} else if (was_cr) {
925+
/*
926+
* Previous round saw CR and it is not followed
927+
* by a LF; emit the CR before processing the
928+
* current character.
929+
*/
930+
output[o++] = '\r';
915931
}
932+
933+
/*
934+
* We may have consumed the last output slot,
935+
* in which case we need to break out of this
936+
* loop; hold the current character before
937+
* returning.
938+
*/
939+
if (*osize_p <= o) {
940+
lf_to_crlf->has_held = 1;
941+
lf_to_crlf->held = ch;
942+
continue; /* break but increment i */
943+
}
944+
945+
if (ch == '\r') {
946+
was_cr = 1;
947+
continue;
948+
}
949+
950+
was_cr = 0;
916951
output[o++] = ch;
917952
}
918953

919954
*osize_p -= o;
920955
*isize_p -= i;
956+
957+
if (!lf_to_crlf->has_held && was_cr) {
958+
lf_to_crlf->has_held = 1;
959+
lf_to_crlf->held = '\r';
960+
}
921961
}
922962
return 0;
923963
}

0 commit comments

Comments
 (0)