For binary streams, ungetc() has to decrement the file position
indicator. fseek() discards the pushed-back character and restores
the file position indicator (`undoes any effects of the ungetc
function').
What position shall `fseek(stream,offset,SEEK_CUR)' use after calling
ungetc() on a binary stream? That is, should the effects of ungetc()
undone before or after retrieving the current file position indicator?
In other words, is
ungetc (0, f);
fseek (f, 0, SEEK_CUR);
equivalent (w.r.t. the file position indicator) to
/* This does not change the file position indicator */
ungetc (0, f);
fflush (f);
fseek (f, 0, SEEK_CUR);
or
/* This decrements the file position indicator by one */
ungetc (0, f);
pos = ftell (f);
fseek (f, pos, SEEK_SET);
What shall the following program print?
------------------------------ cut here ------------------------------
/* This program prints `a' if fseek() undoes the effects of ungetc()
AFTER retrieving the current value of the file position indicator.
It prints `b' if fseek() undoes the effects of ungetc() BEFORE
retrieving the current value of the file position indicator. */
#include <stdio.h>
#include <stdlib.h>
int main (void)
{
FILE *f;
int c;
f = tmpfile (); /* Uses "wb+" mode */
if (f == NULL)
{
perror ("tmpfile()");
return EXIT_FAILURE;
}
fputs ("abc", f);
rewind (f);
fgetc (f); /* a */
ungetc ('X', f);
/* The file position indicator is defined after calling ungetc(), as
f is a binary stream. */
fseek (f, 0L, SEEK_CUR);
c = fgetc (f);
printf ("%c\n", c);
fclose (f);
return EXIT_SUCCESS;
}
--
Eberhard Mattes <mat...@azu.informatik.uni-stuttgart.de>
allow the usual liberal sprinkling of IMOs for the below :).
mat...@iemars7.e-technik.uni-stuttgart.de (Eberhard Mattes) wrote on
19 May 1995 12:36:40 GMT:
>The standard seems to be ambigous w.r.t. fseek(...,SEEK_CUR) for
>binary streams with characters pushed back by ungetc():
Don't think so, the wording is typical standardese, but I can't see it
being ambigious.
>What position shall `fseek(stream,offset,SEEK_CUR)' use after calling
>ungetc() on a binary stream? That is, should the effects of ungetc()
>undone before or after retrieving the current file position indicator?
That really does not matter at all, which is why ISO/C leaves it
unspecified.
7.9.9.2 says:
"A successful call to the fseek function [...] undoes any effects of
the ungetc function on the [...] stream"
ungetc has two effects on a binary stream: It pushes back a character
and it changes the file position indicator. The character gets
discarded (as also noted in 7.9.7.11), and the change of the file
position indicator is undone. Wether that increment by one is done
before or after the rest of the positioning is only a matter of ease
of implementation, the behaviour will remain the same.
Yours
Soenke Behrens
Conner European Technical Support ! Technical Support
Telephone: +44-1294-315333 Telefax: +44-1294-315262 ! USA + Canada:
FaxBack: +44-1294-315205 BBS: +44-1294-315265 ! 1-800-4CONNER
All opinions expressed above are solely my own
> Wether that increment by one is done
> before or after the rest of the positioning is only a matter of ease
> of implementation, the behaviour will remain the same.
I don't believe you :-)
So, what is my sample program supposed to print?
--
Eberhard Mattes <mat...@azu.informatik.uni-stuttgart.de>
>Soenke Behrens writes:
>> Wether that increment by one is done
>> before or after the rest of the positioning is only a matter of ease
>> of implementation, the behaviour will remain the same.
>I don't believe you :-)
Then say so in more words, backed by the standard.
>So, what is my sample program supposed to print?
You are pulling my leg, right?
Soenke
--
fseek(f,offset,SEEK_CUR) has to perform (among other things) the
following three steps:
(R) Retrieve the current file position indicator
(S) Seek to `current file position indicator + offset', without
undoing the effects of ungetc()
(U) Undo the effects of ungetc(); that is, undo the decrements of the
current file position indicator and flush the pushed-back characters
Depending on the sequence of R, S, U, you get different results.
Which one is the correct behavior of fseek(f,offset,SEEK_CUR) on a
binary stream with characters pushed back by ungetc() pending?
There are two possible behaviors w.r.t. the file position indicator:
1. fseek(f,offset,SEEK_CUR) is equivalent to
cur_pos = ftell (f);
fflush (f);
fseek (f, cur_pos + offset, SEEK_SET);
2. fseek(f,offset,SEEK_CUR) is equivalent to
fflush (f); /* undoes the effects of ungetc() */
cur_pos = ftell (f);
fseek (f, cur_pos + offset, SEEK_SET);
Case 1 is achieved by sequences RUS and RSU.
Case 2 is achieved by sequence URS.
I found implementations of case 1, and implementations of case 2.
Which one is the correct one, according to the standard? Or is it undefined?
Case 1 has the advantage that fseek(f,offset,SEEK_CUR) is equivalent
to fseek(f,ftell(f)+offset,SEEK_SET).
Case 2 has the advantage of mainintaing the file's position when
switching from `read mode' to `write mode' of streams open for update,
fseek(f,0,SEEK_CUR) being a no-op w.r.t. the file position indicator.
Here is an example: What should the following program print?
/* ungetc1.c */
mat...@iemars6.e-technik.uni-stuttgart.de (Eberhard Mattes) wrote on
26 May 1995 13:19:00 GMT:
>fseek(f,offset,SEEK_CUR) has to perform (among other things) the
>following three steps:
>(R) Retrieve the current file position indicator
>(S) Seek to `current file position indicator + offset', without
> undoing the effects of ungetc()
>(U) Undo the effects of ungetc(); that is, undo the decrements of the
> current file position indicator and flush the pushed-back characters
>Depending on the sequence of R, S, U, you get different results.
I don't see that. No, the sequence doesn't matter one little bit.
Plus, undoing ungetc() does not flush characters, it discards them:
They do not get written back to the stream. (U) has to have an effect
on the value you got from (R) or will get from (R). With those
amendments, I agree (in principle, never mind details of
implementation).
>Which one is the correct behavior of fseek(f,offset,SEEK_CUR) on a
>binary stream with characters pushed back by ungetc() pending?
>There are two possible behaviors w.r.t. the file position indicator:
>1. fseek(f,offset,SEEK_CUR) is equivalent to
> cur_pos = ftell (f);
> fflush (f);
> fseek (f, cur_pos + offset, SEEK_SET);
>2. fseek(f,offset,SEEK_CUR) is equivalent to
> fflush (f); /* undoes the effects of ungetc() */
> cur_pos = ftell (f);
> fseek (f, cur_pos + offset, SEEK_SET);
>Case 1 is achieved by sequences RUS and RSU.
>Case 2 is achieved by sequence URS.
Ah, I think I see what you are getting at. Now,
fseek(f,offset,SEEK_CUR) is certainly not equivalent to anything with
fflush(f) in it. The reason is:
fflush() is only defined on "an output stream or an update stream in
which the most recent operation was not input". You do not specify
what state your stream is in, very likely "input" because of the use
of ungetc(). The behaviour of fflush() is in this case therefore
undefined, it certainly does not undo the effects of ungetc() (not per
the standard, anyway).
So, let me further clarify this by taking your example and rewriting
it in pseudo-code:
fseek(f, offset, SEEK_CUR) on a binary stream just after an ungetc
could be:
(Your case 1)
j = 0;
j = get_current_position(f) + j;
if (undo_ungetc(f) == TRUE)
j++;
goto_position (f, j + offset);
(Your case 2)
j = 0;
if (undo_ungetc(f) == TRUE)
j++;
j = get_current_position(f) + j;
goto_position (f, j + offset);
undo_ungetc in these examples finds out wether there was an ungetc, if
so it discards the character and returns TRUE. It does not alter the
file position indicator of the stream.
This example is certainly not good code, but it serves to show my
point. There is one big difference between my code and your code: I do
not "undo the undo". Your case 1 strives to alter the file position
indicator by fflush without taking that alteration into account in the
following seek (never mind the incorrect use of fflush). In other
words, you alter the wrong variable.
>Here is an example: What should the following program print?
>/* ungetc1.c */
>/* This program prints `a' if fseek() undoes the effects of ungetc()
> AFTER retrieving the current value of the file position indicator.
> It prints `b' if fseek() undoes the effects of ungetc() BEFORE
> retrieving the current value of the file position indicator. */
Again, you are confused as to how this undoing of the effects of
ungetc should come about.
>#include <stdio.h>
>#include <stdlib.h>
>int main (void)
>{
> FILE *f;
> int c;
> f = tmpfile (); /* Uses "wb+" mode */
> if (f == NULL)
> {
> perror ("tmpfile()");
> return EXIT_FAILURE;
> }
> fputs ("abc", f);
> rewind (f);
> fgetc (f); /* a */
> ungetc ('X', f);
> /* The file position indicator is defined after calling ungetc(), as
> f is a binary stream. */
> fseek (f, 0L, SEEK_CUR);
> c = fgetc (f);
> printf ("%c\n", c);
> fclose (f);
> return EXIT_SUCCESS;
>}
It should print 'b'. I shall try to explain that one more time, with
fewer words:
fseek undoes the effects of an ungetc. How it does that is of no
concern to the standard. Therefore, the _behaviour_ of the program
must be as if you removed the ungetc ('X', f); line from it.
Yours
In article <3q7j6q$e...@imp.demon.co.uk> Soenke Behrens
<sbeh...@contech.demon.co.uk> writes:
>I don't see that. No, the sequence doesn't matter one little bit.
I disagree.
>It should print 'b'. I shall try to explain that one more time, with
>fewer words:
>
>fseek undoes the effects of an ungetc. How it does that is of no
>concern to the standard. Therefore, the _behaviour_ of the program
>must be as if you removed the ungetc ('X', f); line from it.
The question is not *how* fseek undoes the effect of an ungetc,
but rather *when*. According to the description of fseek,
For a binary stream, the new position, measured in characters
from the beginning of the file, is obtained by adding |offset|
to the position specified by |whence|. The specified position
is ... the current value of the file position indicator if
|SEEK_CUR| ....
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.
Referring back to ungetc, we find the following:
A successful call to the |ungetc| function clears the end-of-file
indicator 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; if its value was zero before a call, it is indeterminate
after the call.
This means that, on a binary stream, if the file position indicator
is currently zero and there are characters in the file (and no
errors occur), the sequence:
getc(f);
ungetc('X', f);
definitely leaves the file position indicator set to 0, i.e.,
ftell(f) == 0
must be true.
Mr. Mattes's question, then, is what a subsequent successful:
fseek(f, 0L, SEEK_CUR);
does---does it:
first, compute the current position (0);
next, compute the new position (0 + 0 => 0);
finally, undo the effect of ungetc, possibly
advancing the position indicator to 1 [note 1];
[note 1: `Undoing the effect of ungetc' *traditionally*
(i.e., in K&R C) meant `discarding the ungetc'ed characters
without changing the position'. This leaves the file at
0. The wording of the Standard appears to force a
Quiet Change here.]
or does it:
first, knowing that the seek will be successful, undo the
effect of the ungetc (changing the current position to 1);
next, compute the new position (1 + 0 => 1).
As Mr. Behrens asserts, the final effect is the same (modulo the
caveat in footnote 1 above). On the other hand, if we change the
original code to call ungetc() at 0---that is, if we eliminate the
first getc(f)---we have an ordering problem. If the current position
is computed *before* undoing the ungetc, the answer is `indeterminate',
and `indeterminate + 0' presumably remains indeterminate, so that
the seek itself is to an indeterminate location (presumably resulting
in undefined behavior). If, on the other hand, the library assumes
a successful seek and undoes the ungetc *before* computing the
current location, the result is 0, so that the final position is
zero.
I would also like some clarification as to whether the `undoing
the ungetc' really *does* advance the position indicator even after
a successful seek. A traditional K&R system will print `a', not
`b', for Mr. Mattes's program (and my stdio also does this, so if
this is wrong, I will have to fix that).
--
In-Real-Life: Chris Torek, Berkeley Software Design Inc
Berkeley, CA Domain: to...@bsdi.com +1 510 549 1145