Subject: bug#11631: Head command does not position file pointer correctly for negative line count

From: Jim Meyering <[email-masked]>
Date: Tue, 05 Jun 2012 13:30:15 +0200

Pádraig Brady wrote:
> On 06/05/2012 11:29 AM, Jim Meyering wrote:
>> Anoop Sharma wrote:
>>> Head command does not position file pointer correctly for negative line
>>> count. Here is a demonstration of the problem.
>>>
>>> Step 1 - Create a file with 10 lines in it.
>>> $ yes "ABC" | head -c 40 >ip.txt
>>> $
>>
>> Thank you for the report.  That is indeed a bug.
>> Here's a quick example of how head -n-3 should work:
>>
>>     $ seq 10 > k; (./head -n-3; echo foo; cat) < k
>>     1
>>     2
>>     3
>>     4
>>     5
>>     6
>>     7
>>     foo
>>     8
>>     9
>>     10
>>
>> Before your suggested change, it did this:
>>
>>     $ seq 10 > k; (head -n-3; echo foo; cat) < k
>>     1
>>     2
>>     3
>>     4
>>     5
>>     6
>>     7
>>     foo
>>
>> I note that a similar change is *not* required for the end-relative
>> byte-seekable case:
>>
>>     $ seq 3 > k; (head -c-2; echo foo; cat) < k
>>     1
>>     2
>>     foo
>>     3
>>
>> Here's the start of a proper patch.
>> To come: mention this in NEWS and add a test.
>>
>>>>From 0c156fb347dba3f499ed7b922af1ea357f5558c0 Mon Sep 17 00:00:00 2001
>> From: Jim Meyering <[email-masked]>
>> Date: Tue, 5 Jun 2012 12:24:49 +0200
>> Subject: [PATCH] head: with --lines=-N (-n-N) reset file pointer on seekable
>>  input
>>
>> * src/head.c (elide_tail_lines_seekable): Reset file pointer
>> after printing up to an end-relative line-counted offset.
>> Anoop Sharma reported the problem and suggested the fix.
>> ---
>>  src/head.c | 8 ++++++++
>>  1 file changed, 8 insertions(+)
>>
>> diff --git a/src/head.c b/src/head.c
>> index d7e83b7..75a69d8 100644
>> --- a/src/head.c
>> +++ b/src/head.c
>> @@ -667,6 +667,14 @@ elide_tail_lines_seekable (const char *pretty_filename, int fd,
>>                   Don't bother testing for failure for such a small amount.
>>                   Any failure will be detected upon close.  */
>>                fwrite (buffer, 1, n + 1, stdout);
>> +
>> +              /* Set file pointer to the byte after what we've output.  */
>> +              if (lseek (fd, start_pos + n + 1, SEEK_SET) < 0)
>
> s/start_pos/pos/ ?

Oh!  Good catch.  Thanks!  You're right.
Now I'll have to construct a test that exercises that bug, too.