Mail Archives: djgpp-workers/2013/07/17/16:46:30
Am 17.07.2013 17:24, schrieb Eli Zaretskii:
>> Date: Wed, 17 Jul 2013 01:01:26 +0200
>> From: Juan Manuel Guerrero <juan DOT guerrero AT gmx DOT de>
>>
>> Please inspect the code snippet below:
>>
>> #include <stdio.h>
>>
>> int main(void)
>> {
>> char buffer[1024];
>> FILE *f = fopen("foobar.txt", "w");
>>
>> clearerr(f);
>>
>> if (fgets(buffer, sizeof(buffer), f) == NULL)
>> printf("EOF encountered before data\n");
>>
>> printf("ferror = %s\n", ferror(f) ? "TRUE" : "FALSE");
>> printf("feof = %s\n", feof(f) ? "TRUE" : "FALSE");
>>
>> return 0;
>> }
>>
>>
>> The code snippet is not arbitrary (especially the "w" mode instead of the "w+"
>> mode in the fopen function) but represents a compilable and working version of
>> the code produced by the lua interpreter for the first two lines of the
>> following lua code snippet:
>>
>> local f = io.open("foobar.txt", "w")
>> local r, m, c = f:read()
>> assert(r == nil and ismsg(m) and type(c) == "number")
>>
>>
>> The above code is part of a test suite and it shall fail because it tries to
>> read from a file opened to be written. The second line fails and initializes
>> the variables in such a way that the assert is not triggert (the data is a
>> error message and the file descriptor, but that is of no importance here).
>> This is the way the test shall work and this is the way the code works if lua
>> has been compiled on linux. If lua is compiled using any version of djgpp,
>> the second line:
>> local r, m, c = f:read()
>> behaves in a different way (it does not fail, among other things) and the
>> variables are initialized with nonsense data making the following assertion
>> to be triggert and thus aborting the complete test suite.
>>
>> The reason for the different behavior of lua's :read() function is the
>> different way the ferror function has been implemented on linux and djgpp.
>>
>> The issue concerns the fread, fwrite, __putc and __getc functions only.
>> These functions manipulate the file stream FILE *. Functions like read,
>> _read and dos_read are not involved because they work with the file descriptor.
>> If these functions fail due to accessing the file with wrong file mode,
>> they set the appropriate dos error number.
>> Of course, ferror can only fail for those functions that use the file stream.
>>
>> The patch below will fix the issue for read and write functions.
>> As usual, suggestions, objections, comments are welcome.
> What standard mandates that reading from a file stream open in "w"
> mode shall set the error flag for the stream?
>
> DJGPP currently sets the EOF flag, not the error flag. Why is that
> wrong?
According to http://pubs.opengroup.org/onlinepubs/009695399/functions/fgets.html
RETURN VALUE
Upon successful completion, fgets() shall return s. If the stream is at end-of-file,
the end-of-file indicator for the stream shall be set and fgets() shall return a null
pointer. If a read error occurs, the error indicator for the stream shall be set,
fgets() shall return a null pointer.
According to http://pubs.opengroup.org/onlinepubs/009695399/functions/fputs.html
RETURN VALUE
Upon successful completion, fputs() shall return a non-negative number. Otherwise,
it shall return EOF, set an error indicator for the stream.
According to http://pubs.opengroup.org/onlinepubs/009695399/functions/fread.html
RETURN VALUE
Upon successful completion, fread() shall return the number of elements successfully
read which is less than nitems only if a read error or end-of-file is encountered.
If size or nitems is 0, fread() shall return 0 and the contents of the array and the
state of the stream remain unchanged. Otherwise, if a read error occurs, the error
indicator for the stream shall be set
According to http://pubs.opengroup.org/onlinepubs/009695399/functions/fwrite.html
RETURN VALUE
The fwrite() function shall return the number of elements successfully written,
which may be less than nitems if a write error is encountered. If size or nitems
is 0, fwrite() shall return 0 and the state of the stream remains unchanged.
Otherwise, if a write error occurs, the error indicator for the stream shall be set,
For IEEE Std 1003.1-2001-conforming systems all the functions also shall set errno.
It is a matter of fact that the sample code posted in the previous mail
behaves as described by me for linux and cygwin. And this behavior is
exploited by other programs like lua. I have inspected __getc, __putc,
fwrite and fread and neither of them set EOF. In the best case some of
them may return EOF to the calling context to signal a failure but the
_flag member (error indicator for the stream) is never set neither to
_IOEOF nor to _IOERR AFAIK. I have not tried it mingw but I presume it
will behave the same way than linux and cygwin.
It may be objectionable if __getc and __putc were the right places to fix
the issue. I will move the fix into fgets and fputs, the same way I have
done for fwrite and fread. By fixing it in the auxiliary functions
__getc and __putc, my intention was to have it fixed every where and for
all times.
BTW as can be seen for fgets if the stream is at end-of-file, the end-of-file
indicator for the stream shall be set apart from returning a NULL pointer.
So there is much work to be done.
IMHO it is better to try to fix the library than to clobber the
source code of some program to get it compiled with djgpp or the
day may come when djgpp become completely useless and obsolete.
Regards,
Juan M. Guerrero
- Raw text -