At some point between Diffutils 2.8.7 and 2.9, the code that handles binary files was removed from io.c. The changes below resurrect the correct behavior. To accomplish this, I needed to add the binary-io module, and make changes there as well. Patches are below.
Thanks. 2012-05-12 Eli Zaretskii <[email protected]> * lib/binary-io.h (SET_BINARY) [O_BINARY]: Return the previous mode. (UNSET_BINARY): New macro, to reset I/O to text mode. (SET_BINARY, UNSET_BINARY): Include _WIN32 in the conditional for MS systems. * src/io.c: Include binary-io.h. (sip, read_files): Switch file I/O to binary mode and back as appropriate, to support binary files on systems that distinguish between text and binary I/O. --- src/io.c~0 2011-08-15 08:24:38.000000000 +0300 +++ src/io.c 2012-05-12 18:55:24.201750000 +0300 @@ -22,6 +22,7 @@ #include <cmpbuf.h> #include <file-type.h> #include <xalloc.h> +#include <binary-io.h> /* Rotate an unsigned value to the left. */ #define ROL(v, n) ((v) << (n) | (v) >> (sizeof (v) * CHAR_BIT - (n))) @@ -110,12 +111,25 @@ sip (struct file_data *current, bool ski if (! skip_test) { /* Check first part of file to see if it's a binary file. */ - - /* FIXME: if O_BINARY, this should revert to text mode - if the file is not binary. */ + bool binary_file; + int prev_mode = SET_BINARY (current->desc); file_block_read (current, current->bufsize); - return binary_file_p (current->buffer, current->buffered); + binary_file = binary_file_p (current->buffer, current->buffered); + if (prev_mode != O_BINARY) + { + /* Revert to text mode and seek back to the beginning to + reread the file. Use relative seek, since file + descriptors like stdin might not start at offset + zero. */ + + if (lseek (current->desc, -current->buffered, SEEK_CUR) == -1) + pfatal_with_name (current->name); + (void) UNSET_BINARY (current->desc); + current->buffered = 0; + current->eof = false; + } + return binary_file; } } @@ -761,7 +775,8 @@ read_files (struct file_data filevec[], } if (appears_binary) { - /* FIXME: If O_BINARY, this should set both files to binary mode. */ + (void) SET_BINARY (filevec[0].desc); + (void) SET_BINARY (filevec[1].desc); return true; } --- lib/binary-io.h~1 2012-05-12 17:31:43.639250000 +0300 +++ lib/binary-io.h 2012-05-12 18:19:53.842375000 +0300 @@ -26,9 +26,14 @@ #include <stdio.h> /* SET_BINARY (fd); - changes the file descriptor fd to perform binary I/O. */ + changes the file descriptor fd to perform binary I/O, returns + the previous I/O mode. + + UNSET_BINARY (fd); + changes the file descriptor fd to perform text I/O, returns + the previous I/O mode. */ #if O_BINARY -# if defined __EMX__ || defined __DJGPP__ || defined __CYGWIN__ +# if defined __EMX__ || defined __DJGPP__ || defined __CYGWIN__ || defined _WIN32 # include <io.h> /* declares setmode() */ # else # define setmode _setmode @@ -40,13 +45,15 @@ /* Avoid putting stdin/stdout in binary mode if it is connected to the console, because that would make it impossible for the user to interrupt the program through Ctrl-C or Ctrl-Break. */ -# define SET_BINARY(fd) ((void) (!isatty (fd) ? (setmode (fd, O_BINARY), 0) : 0)) +# define SET_BINARY(fd) (!isatty (fd) ? setmode (fd, O_BINARY) : -1) # else -# define SET_BINARY(fd) ((void) setmode (fd, O_BINARY)) +# define SET_BINARY(fd) (setmode (fd, O_BINARY)) # endif +# define UNSET_BINARY(fd) (setmode (fd, O_TEXT)) #else /* On reasonable systems, binary I/O is the default. */ -# define SET_BINARY(fd) /* do nothing */ ((void) 0) +# define SET_BINARY(fd) /* do nothing */ (O_BINARY) +# define UNSET_BINARY(fd) /* do nothing */ (-1) #endif #endif /* _BINARY_H */
