@@ -156,6 +156,24 @@ int xdl_blankline(const char *line, long size, long flags)
156156 return (i == size );
157157}
158158
159+ /*
160+ * Have we eaten everything on the line, except for an optional
161+ * CR at the very end?
162+ */
163+ static int ends_with_optional_cr (const char * l , long s , long i )
164+ {
165+ int complete = s && l [s - 1 ] == '\n' ;
166+
167+ if (complete )
168+ s -- ;
169+ if (s == i )
170+ return 1 ;
171+ /* do not ignore CR at the end of an incomplete line */
172+ if (complete && s == i + 1 && l [i ] == '\r' )
173+ return 1 ;
174+ return 0 ;
175+ }
176+
159177int xdl_recmatch (const char * l1 , long s1 , const char * l2 , long s2 , long flags )
160178{
161179 int i1 , i2 ;
@@ -170,7 +188,8 @@ int xdl_recmatch(const char *l1, long s1, const char *l2, long s2, long flags)
170188
171189 /*
172190 * -w matches everything that matches with -b, and -b in turn
173- * matches everything that matches with --ignore-space-at-eol.
191+ * matches everything that matches with --ignore-space-at-eol,
192+ * which in turn matches everything that matches with --ignore-cr-at-eol.
174193 *
175194 * Each flavor of ignoring needs different logic to skip whitespaces
176195 * while we have both sides to compare.
@@ -204,6 +223,14 @@ int xdl_recmatch(const char *l1, long s1, const char *l2, long s2, long flags)
204223 i1 ++ ;
205224 i2 ++ ;
206225 }
226+ } else if (flags & XDF_IGNORE_CR_AT_EOL ) {
227+ /* Find the first difference and see how the line ends */
228+ while (i1 < s1 && i2 < s2 && l1 [i1 ] == l2 [i2 ]) {
229+ i1 ++ ;
230+ i2 ++ ;
231+ }
232+ return (ends_with_optional_cr (l1 , s1 , i1 ) &&
233+ ends_with_optional_cr (l2 , s2 , i2 ));
207234 }
208235
209236 /*
@@ -230,9 +257,16 @@ static unsigned long xdl_hash_record_with_whitespace(char const **data,
230257 char const * top , long flags ) {
231258 unsigned long ha = 5381 ;
232259 char const * ptr = * data ;
260+ int cr_at_eol_only = (flags & XDF_WHITESPACE_FLAGS ) == XDF_IGNORE_CR_AT_EOL ;
233261
234262 for (; ptr < top && * ptr != '\n' ; ptr ++ ) {
235- if (XDL_ISSPACE (* ptr )) {
263+ if (cr_at_eol_only ) {
264+ /* do not ignore CR at the end of an incomplete line */
265+ if (* ptr == '\r' &&
266+ (ptr + 1 < top && ptr [1 ] == '\n' ))
267+ continue ;
268+ }
269+ else if (XDL_ISSPACE (* ptr )) {
236270 const char * ptr2 = ptr ;
237271 int at_eol ;
238272 while (ptr + 1 < top && XDL_ISSPACE (ptr [1 ])
0 commit comments