879
880
struct lf_to_crlf_filter {
881
struct stream_filter filter;
882
- unsigned want_lf:1;
882
+ unsigned has_held:1;
883
+ char held;
884
};
885
886
static int lf_to_crlf_filter_fn(struct stream_filter *filter,
890
size_t count, o = 0;
891
struct lf_to_crlf_filter *lf_to_crlf = (struct lf_to_crlf_filter *)filter;
892
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;
901
}
902
903
/* We are told to drain */
907
}
908
909
count = *isize_p;
905
- if (count) {
910
+ if (count || lf_to_crlf->has_held) {
911
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
+
919
for (i = 0; o < *osize_p && i < count; i++) {
920
char ch = input[i];
921
+
922
if (ch == '\n') {
923
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';
931
}
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;
951
output[o++] = ch;
952
}
953
954
*osize_p -= o;
955
*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
+ }
961
}
962
return 0;
963
}