From tplate at blackmesacapital.com  Tue May 31 19:13:42 2005
From: tplate at blackmesacapital.com (tplate@blackmesacapital.com)
Date: Tue May 31 19:13:50 2005
Subject: [Rd] (PR#7899) seek(con, 0, "end", rw="r") does not always work
Message-ID: <20050531171342.E4295A274@slim.kubism.ku.dk>

Uwe Ligges wrote:
> Tony Plate wrote:
> 
>> ligges@statistik.uni-dortmund.de wrote:
>>
>>> tplate@blackmesacapital.com wrote:
>>>
>>>
>>>> I've noticed that seek(con, 0, "end", rw="r") on a file connection 
>>>> does not always work correctly after a write (R 2.1.0 on Windows).
>>>>
>>>> [Is a call to fflush() needed inside file_seek() in 
>>>> main/connections.c?]
>>>
>>>
>>>
>>>
>>>
>>> If you have an idea where to fflush() precisely and your patch works, 
>>> please tell it! I'll happily run some test cases where seeking matters.
>>>
>>
>> I couldn't see why the current code was returning a bad value under 
>> some conditions.  (That's why didn't offer anything more than a 
>> suggestion).  My suggestion to use an fflush() was a guess (hence the 
>> question mark, but evidence for the guess being correct was that doing 
>> a flush at the R command line made the whole thing work correctly.)  
>> To be safe, I would try to put a flush() right at the beginning of 
>> file_seek(), before the call to f_tell().  I tried this, and with the 
>> modification the test case I gave produced correct output.  Here's how 
>> the beginning of my modified file_seek() function (in 
>> main/connections.c) looks:
> 
>  >
> 
>> static double file_seek(Rconnection con, double where, int origin, int 
>> rw)
>> {
>>     Rfileconn this = con->private;
>>     FILE *fp = this->fp;
>> #if defined(HAVE_OFF_T) && defined(__USE_LARGEFILE)
>>     off_t pos;
>> #else
>> #ifdef Win32
>>     off64_t pos;
>> #else
>>     long pos;
>> #endif
>> #endif
>>     int whence = SEEK_SET;
>>     fflush(fp);
>>     pos = f_tell(fp);
>>
>>     /* make sure both positions are set */
>>
> 
> 
> Works for your example, but I found another one where it introduces a 
> worse bug when using origin="current". Hence it's not that easy.
> 
> After reviewing this issue more closely, I think writeLines() into a 
> binary connection might be the real problem and a misuse in this case. 
> See the last paragrpah in the Details Section of ?writeLines. Hence, 
> this might also be an issue related to the text mode connection problem 
> on Windows.
> 
> Using simple writeChar and readChar statements works as expected for me 
> (at least, I was not able to produce anything unexpected). I'm no longer 
> convinced that this is a bug in R.

I see the same (buggy) behavior when I replace the writeLines() 
statements by writeChar() statments (but continue using readLines()).  I 
also see the same buggy behavior when I explicitly supply a 'sep' 
argument to writeLines().  Transcripts of both of these are below. 
[Also, in both cases, calling the R function flush() at indicated 
position in the transcript results in correct output.]

Regarding the documentation for writeLines, it states:

      Normally 'writeLines' is used with a text connection, and the
      default separator is converted to the normal separator for that
      platform (LF on Unix/Linux, CRLF on Windows, CR on Classic MacOS).
       For more control, open a binary connection and specify the
      precise value you want written to the file in 'sep'.  For even
      more control, use 'writeChar' on a binary connection.

The sentence beginning "For more control" seems to permit the use of 
writeLines() for binary connections.  What suggested to you that it was 
a misuse?


 > # seek(, rw="r") on a file does not always work a write
 > # even when sep="\n" is supplied to writeLines
 > f <- file("tmp3.txt", "w+b")
 > # Write something earlier in the file
 > seek(f, 10, rw="w")
[1] 0
 > writeLines(c("ghi", "jkl"), f, sep="\n")
 > seek(f, 20, rw="w")
[1] 18
 > writeLines(c("abc"), f, sep="\n")
 > seek(f, 0, "end", rw="w")
[1] 24
 > # Try to read at the end of the file
 > seek(f, 0, "end", rw="r")
[1] 0
 > readLines(f, -1)
character(0)
 > seek(f, 0, "end", rw="w")
[1] 18
 > # write something at the end of the file
 > writeLines(c("def"), f, sep="\n")
 > # Try to read at the end of the file
 > # flush(f) # flushing here makes the seek work correctly
 > seek(f, 0, "end", rw="r")
[1] 24
 > seek(f, NA, rw="r") # ***WRONG*** (should return 28)
[1] 24
 > readLines(f, -1) # ***WRONG*** (should return character(0))
[1] "def"
 > seek(f, 20, rw="r")
[1] 28
 > readLines(f, -1)
[1] "abc" "def"
 > seek(f, 0, "end", rw="r") # now it works correctly
[1] 28
 > seek(f, NA, rw="r")
[1] 28
 > readLines(f, -1)
character(0)
 > close(f)
 >
 > # seek(, rw="r") on a file does not always work a write
 > # even when writeChar is used instead of writeLines
 > f <- file("tmp3.txt", "w+b")
 > # Write something earlier in the file
 > seek(f, 10, rw="w")
[1] 0
 > writeChar(c("ghi\n", "jkl\n"), f, eos=NULL)
 > seek(f, 20, rw="w")
[1] 18
 > writeChar(c("abc\n"), f, eos=NULL)
 > seek(f, 0, "end", rw="w")
[1] 24
 > # Try to read at the end of the file
 > seek(f, 0, "end", rw="r")
[1] 0
 > readLines(f, -1)
character(0)
 > seek(f, 0, "end", rw="w")
[1] 18
 > # write something at the end of the file
 > writeChar(c("def\n"), f, eos=NULL)
 > # Try to read at the end of the file
 > # flush(f) # flushing here makes the seek work correctly
 > seek(f, 0, "end", rw="r")
[1] 24
 > seek(f, NA, rw="r") # ***WRONG*** (should return 28)
[1] 24
 > readLines(f, -1) # ***WRONG*** (should return character(0))
[1] "def"
 > seek(f, 20, rw="r")
[1] 28
 > readLines(f, -1)
[1] "abc" "def"
 > seek(f, 0, "end", rw="r") # now it works correctly
[1] 28
 > seek(f, NA, rw="r")
[1] 28
 > readLines(f, -1)
character(0)
 > close(f)
 >
 > version
          _
platform i386-pc-mingw32
arch     i386
os       mingw32
system   i386, mingw32
status
major    2
minor    1.0
year     2005
month    04
day      18
language R
 >

-- Tony Plate


[Rd] (PR#7899) seek(con, 0, "end", rw="r") does not always work
tplate@blackmesacapital.com