On 06/12/2012 01:04 AM, Ben Pfaff wrote: > Eric Blake <[email protected]> writes: > >> Wrong. Pretty much every libc out there lets you ungetc() more than one >> byte. > > Does that include glibc? Then there is a bug in the manual, > which says: > > The GNU C library only supports one character of > pushbackâin other words, it does not work to call ungetc > twice without doing input in between. > > in the description of ungetc().
That's the glibc documentation and I agree it is inaccurate; the Linux
man-pages project is better:
ungetc() pushes c back to stream, cast to unsigned char, where
it is
available for subsequent read operations. Pushed-back
characters will
be returned in reverse order; only one pushback is guaranteed.
And this simple program proves that most libc know how to push back more
than one byte, whether or not they differ from the original contents,
and especially in the common case where the byte still fits in the
buffer. It's the corner case where the bytes being pushed back differ
from the backing store, and where they don't fit in the normal buffer
(perhaps because you have used setvbuf or friends), and therefore libc
has to malloc() some pushback storage, and if the malloc fails then so
does the ungetc().
$ cat foo.c
#include <stdio.h>
int main(void)
{
char buf[10];
if (fseek(stdin, 0, SEEK_CUR))
return 1;
if (fread(buf, 1, sizeof(buf), stdin) != 10)
return 2;
if (ungetc(buf[9], stdin) != buf[9])
return 3;
if (ungetc(buf[8], stdin) != buf[8])
return 4;
if (getchar() != buf[8])
return 5;
if (getchar() != buf[9])
return 6;
if (ungetc(buf[9] + 1, stdin) != buf[9] + 1)
return 7;
if (ungetc(buf[8] + 1, stdin) != buf[8] + 1)
return 8;
if (getchar() != buf[8] + 1)
return 9;
if (getchar() != buf[9] + 1)
return 10;
return 0;
}
$ ./foo < foo.c; echo $?
0
--
Eric Blake [email protected] +1-919-301-3266
Libvirt virtualization library http://libvirt.org
signature.asc
Description: OpenPGP digital signature
