JTC1/SC22/WG14
N776
Document Number: WG14 N776/J11 97-140
C9X Revision Proposal
=====================
Title: fseek & ungetc
Author: Fred J. Tydeman
Author Affiliation: Tydeman Consulting
Postal Address: 3711 Del Robles Dr., Austin, TX 78727-1814
E-mail Address: tydeman@tybor.com
Telephone Number: +1 (512) 255-8696
Fax Number: +1 (512) 255-8696
Sponsor: NCITS/J11
Date: 1997-09-25
Document History: N/A.
Proposal Category:
__ Editorial change/non-normative contribution
_Y Correction
__ New feature
__ Addition to obsolescent feature list
__ Addition to Future Directions
__ Other (please specify) ______________________________
Area of Standard Affected:
__ Environment
__ Language
__ Preprocessor
_Y Library
__ Macro/typedef/tag name
_Y Function
__ Header
__ Other (please specify) ______________________________
Prior Art: Many compilers already support one or the other
interpretations.
Target Audience: All users.
Related Documents (if any): SC22WG14.2595__________________
Proposal Attached: _Y Yes __ No, but what's your interest?
Abstract: Pick a defined behaviour for the interaction between
fseek and ungetc for binary streams.
Proposal:
In 7.9.9.2 The fseek Function, change:
"A successful call to the fseek function clears the
end-of-file indicator for the stream and undoes any effects
of the ungetc function on the same stream."
to:
Option A:
"A successful call to the fseek function clears the
end-of-file indicator for the stream, then undoes any
effects of the ungetc function on the same stream, and then
uses the current file position to set the new file position
indicator."
or to:
Option B:
"A successful call to the fseek function clears the
end-of-file indicator for the stream, uses the current file
position to determine the new file position indicator, and
then undoes any effects of the ungetc function on the same
stream."
Rationale:
The current wording in unclear as to two items:
1) End-of-file is set, ungetc is done (which clears the
end-of-file indicator), and then fseek of SEEK_CUR is done.
fseek has contradictory requirements: clear end-of-file
indicator and undoes ANY effects of ungetc (which would set
end-of-file indicator for this case).
2) The order is not specified for getting the current value
of the file position indicator and undoing the effects of
ungetc to determine the new file position indicator.
I am offering both choices on how to fix it as we could not
reach informal consensus from the few who responded via
email at around SC22WG14.2595 (June, 1996).
I believe that option A is the correct behaviour based upon
what ungetc does for fseek. fseek causes ungetc to discard
any pushed back characters and ungetc sets the value of the
file position indicator to be the same after discarding all
pushed-back characters as it was before the characters were
pushed back.
Here are two programs to show the interactions:
/*
* Question on meaning of fseek after ungetc with binary files.
*
* 7.9.9.2 The fseek Function says
*
* "A successful call to the fseek function clears the end-of-file
* indicator for the stream and undoes any effects of the ungetc
* function on the same stream."
*
* 7.9.7.11 The ungetc Function says
*
* "A successful intervening call (with the stream pointed to by stream)
* to a file positioning function (fseek, fsetpos, or rewind) discards
* any pushed-back characters for the stream."
*
* "The value of the file position indicator for the stream after
* reading or discarding all pushed-back characters shall be the same
* as it was before the characters were pushed back."
*
* "For a binary stream, its file position indicator is decremented
* by each successful call to the ungetc function; ..."
*
* The question is:
*
* When one does a relative seek (SEEK_CUR) just after an ungetc, what is
* the current value of the file position indicator? Is it the value at
* the time fseek is entered, or is it the value after the effects of
* ungetc have been undone? Or, something else?
*
* In terms of this program, is the final print a 7 or 8?
*
* The three ftell's print:
* 8, 8, 8 Borland Turbo C 2.0, Symantec C/C++ 7
* 8, 7, 8 Borland C/C++ 4.0
* 8, -, - emx 08.h (Cannot ungetc)
* 8, 7, 7 emx 09.b, 09.c
*/
#include <stdio.h> /* printf(), ftell(), fseek(), ungetc(), FILE */
#include <errno.h> /* errno */
int main(void){
long pos0 = 8L;
long pos1;
long pos2;
long pos3;
int rc;
int c;
FILE *f;
f = tmpfile(); /* create a temp binary file */
if( NULL == f ){ perror("cannot tmpfile"); goto death; }
rc = fputs("0123456789", f); /* write some chars to that file */
if( EOF == rc ){ perror("cannot fputs"); goto death; }
rc = fflush(f); /* make sure it is written */
if( EOF == rc ){ perror("cannot fflush"); goto death; }
errno = 0;
rewind(f); /* set file position indicator */
if( errno ){ perror("cannot rewind"); goto death; }
rc = fseek(f,pos0,SEEK_SET); /* set file position indicator */
if( rc ){ perror("cannot fseek"); goto death; }
pos1 = ftell(f); /* should be 8 */
if( -1L == pos1 ){ perror("cannot ftell"); goto death; }
(void)printf("...After seek to %ld, ftell says %ld\n", pos0, pos1 );
c = ungetc('x',f); /* decrement file position indicator */
if( EOF == c ){ perror("cannot ungetc"); goto death; }
pos2 = ftell(f); /* should be 7 */
if( -1L == pos2 ){ perror("cannot ftell"); goto death; }
(void)printf("...After ungetc, ftell says %ld; should be %ld\n",
pos2, pos1-1L );
rc = fseek(f,0L,SEEK_CUR); /* seek relative to current file position */
if( rc ){ perror("cannot fseek"); goto death; }
pos3 = ftell(f); /* what is it? 7 or 8 */
if( -1L == pos3 ){ perror("cannot ftell"); goto death; }
(void)printf("...After relative seek of 0, ftell says %ld\n", pos3 );
death:;
return 0;
}
/*
* Question on meaning of: At end of file, ungetc, then fseek current.
*
* 7.9.9.2 The fseek Function says
*
* "A successful call to the fseek function clears the end-of-file
* indicator for the stream and undoes any effects of the ungetc
* function on the same stream."
*
* 7.9.7.11 The ungetc Function says
*
* "A successful call to the ungetc functions clears the end-of-file
* indicator for the stream."
*
* The question is:
*
* If one is at the end-of-file (so the end-of-file indicator is set),
* one does an ungetc (which clears the end-of-file indicator), then one
* does a fseek to the current position, is the end-of-file indicator set?
* (Assumes the file position indicator for the stream after discarding
* all pushed-back characters is the same as it was before the characters
* were pushed back is the effect of fseek after ungetc. Assumes can ungetc
* while end-of-file is true.)
* "undoes any effects of the ungetc function" implies set (since ungetc
* cleared end-of-file and that effect is now undone)
* "fseek function clears the end-of-file indicator" implies clear.
* Seems like a contradiction.
*
* The three ftell's and EOF print:
* 10, 10, -, - Borland Turbo C 2.0 (EOF still set after ungetc)
* 10, 10, -, - Symantec C/C++ 7 (cannot ungetc at EOF)
* 10, 10, 10, False Borland C/C++ 4.0
* 10, 10, 9, False emx 08.h, 09.b, 09.c
*/
#include <stdio.h> /* printf(), ftell(), fseek(), ungetc(), FILE */
#include <errno.h> /* errno */
int main(void){
long pos1;
long pos2;
long pos3;
int eof1;
int eof2;
int eof3;
int err1;
int err2;
int err3;
int rc;
int c;
FILE *f;
static const char b[2][6] = { {"False"}, {"True "} };
f = tmpfile(); /* create a temp binary file */
if( NULL == f ){ perror("cannot tmpfile"); goto death; }
rc = fputs("0123456789", f); /* write some chars to that file */
if( EOF == rc ){ perror("cannot fputs"); goto death; }
rc = fflush(f); /* make sure it is written */
if( EOF == rc ){ perror("cannot fflush"); goto death; }
errno = 0;
rewind(f); /* go to start of file */
if( errno ){ perror("cannot rewind"); goto death; }
rc = fseek(f,9L,SEEK_SET); /* go to just before end of file */
if( rc ){ perror("cannot fseek to before end"); goto death; }
c = fgetc(f); /* get to end-of-file */
if( '9' != c ){ perror("fgetc of '9' failed"); goto death; }
pos1 = ftell(f); /* should be 10? */
if( -1L == pos1 ){ perror("cannot ftell"); goto death; }
(void)printf("...After seek to end, ftell says %ld\n", pos1 );
c = fgetc(f); /* get at end-of-file */
if( EOF != c ){ perror("fgetc at EOF not EOF"); goto death; }
eof1 = feof(f); /* make sure at EOF */
if( 0 == eof1 ){ perror("EOF not set at EOF"); goto death; }
err1 = ferror(f); /* make sure not past EOF */
if( 0 != err1 ){ perror("went past EOF"); goto death; }
pos2 = ftell(f); /* should be 10 or 11? */
if( -1L == pos2 ){ perror("cannot ftell"); goto death; }
(void)printf("...After fgetc, ftell says %ld\n", pos2 );
c = ungetc('x',f); /* reset end-of-file indicator */
if( EOF == c ){ perror("cannot ungetc at EOF"); goto death; }
eof2 = feof(f); /* make sure not at EOF */
if( 0 != eof2 ){ perror("EOF still set after ungetc"); goto death; }
err2 = ferror(f); /* make sure not past EOF */
if( 0 != err2 ){ perror("error after ungetc"); goto death; }
rc = fseek(f,0L,SEEK_CUR); /* seek to where we are */
if( rc ){ perror("cannot fseek"); goto death; }
eof3 = feof(f); /* What is EOF indicator? */
(void)printf("...EOF after fseek after ungetc after EOF is: %s\n",
b[!!eof3] );
err3 = ferror(f); /* What is ERROR indicator? */
(void)printf("...ERROR after fseek after ungetc after EOF is: %s\n",
b[!!err3] );
pos3 = ftell(f); /* What is position? */
(void)printf("...Final ftell is %ld\n", pos3 );
death:;
return 0;
}