summaryrefslogtreecommitdiff
path: root/src/wc.c
diff options
context:
space:
mode:
authorJim Meyering <jim@meyering.net>1995-02-09 17:05:43 +0000
committerJim Meyering <jim@meyering.net>1995-02-09 17:05:43 +0000
commit05d1bec3e5a34449ffde7f71648084069b1319f5 (patch)
tree3b561f642ae9a632ad8fe11bf0eba17cf362ce3d /src/wc.c
parentb968f43e9508fc16e225b749ce3368071630065a (diff)
downloadcoreutils-05d1bec3e5a34449ffde7f71648084069b1319f5.tar.xz
(wc): Don't overcount the number of bytes when reading from
a regular file on stdin with file pointer not at BOF. From Karl Heuer.
Diffstat (limited to 'src/wc.c')
-rw-r--r--src/wc.c20
1 files changed, 15 insertions, 5 deletions
diff --git a/src/wc.c b/src/wc.c
index 7086c96c0..34706ae67 100644
--- a/src/wc.c
+++ b/src/wc.c
@@ -201,19 +201,29 @@ wc (fd, file)
register int bytes_read;
register int in_word = 0;
register unsigned long lines, words, chars;
- struct stat stats;
lines = words = chars = 0;
/* When counting only bytes, save some line- and word-counting
- overhead. If FD is a `regular' Unix file, using fstat is enough
+ overhead. If FD is a `regular' Unix file, using lseek is enough
to get its size in bytes. Otherwise, read blocks of BUFFER_SIZE
- bytes at a time until EOF. */
+ bytes at a time until EOF.
+
+ NOTE: using fstat and stats.st_size (and omitting the lseek calls)
+ over counts when the file is not positioned at the beginning.
+ For example the command `(dd skip=9999; wc -c) < /etc/group'
+ should make wc report `0' bytes. */
+
if (print_chars && !print_words && !print_lines)
{
- if (fstat (fd, &stats) == 0 && S_ISREG (stats.st_mode))
+ struct stat stats;
+ off_t current_pos, end_pos;
+
+ if (fstat (fd, &stats) == 0 && S_ISREG (stats.st_mode)
+ && (current_pos = lseek (fd, (off_t)0, SEEK_CUR)) != -1
+ && (end_pos = lseek (fd, (off_t)0, SEEK_END)) != -1)
{
- chars = stats.st_size;
+ chars = end_pos - current_pos;
}
else
{