-1

Suppose I have a FILE* created by fopencookie, what happens if I call ungetc on the FILE*? Suppose I've setvbuf on the FILE* as _IONBF to make it unbuffered. Looks like the fopencookie doesn't support a handler for ungetc.

The background is I want to run scanf on istream, see scanf on an istream object. One suggestion is to use fopencookie and I was trying to wrap istream as FILE* by fopencookie, the problem comes out is, I need to make sure the FILE* doesn't buffer anything, however, scanf will at least read one character ahead when parsing fields whose width is unknown, e.g. for %d it will continue to read until find space or end-of-line. I assume scanf will put the character back to the FILE* by ungetc, in which case I need to put this character back to the istream as well. Is it possible to know which character scanf ungets? Thanks.

Community
  • 1
  • 1
Kan Li
  • 8,557
  • 8
  • 53
  • 93
  • Is your name correct? Than you can do the science. Just try it out. Alternative, look at the libc sources... – Deduplicator Jun 20 '14 at 01:28
  • Like @Deduplicator said... `Just Try It`. You'll learn more from a 5 minute test and possible success or failure than you will from hours of reading and pondering. You won't break it, but if you do, you get to keep the pieces to see what went wrong! Experiment! Make mistakes! Like Asimov said, most discoveries aren't from "`I wonder`", but from "`hmm, that's odd`". – lornix Jun 20 '14 at 01:47
  • @lornix, well, I changed the title a little bit to reflect the how-to nature of my question. – Kan Li Jun 20 '14 at 02:18

1 Answers1

1

fopencookie is a GNU extension which, as far as I know, exists in no other C library.

The GNU libc implementation of stdio is decidedly hairier than it ought to be because of an ancient (pre-EGCS, if that means anything to you) attempt to make FILE objects directly usable as C++ streambuf objects - no foolin'! - but the answer to your question may be found here: https://sourceware.org/git/?p=glibc.git;a=blob;f=libio/genops.c#l722 (the implementation of ungetc being named _IO_sputbackc is one of the remaining vestiges of that ancient attempt) I'll quote the code, it's short:

722 int
723 _IO_sputbackc (fp, c)
724      _IO_FILE *fp;
725      int c;
726 {
727   int result;
728
729   if (fp->_IO_read_ptr > fp->_IO_read_base
730       && (unsigned char)fp->_IO_read_ptr[-1] == (unsigned char)c)
731     {
732       fp->_IO_read_ptr--;
733       result = (unsigned char) c;
734     }
735   else
736     result = _IO_PBACKFAIL (fp, c);
737
738   if (result != EOF)
739     fp->_flags &= ~_IO_EOF_SEEN;
740
741   return result;
742 }

What this is saying is that if the character pushed back is identical to the character right behind the read pointer in the FILE object's buffer, it just decrements the read pointer once; otherwise, _IO_PBACKFAIL is called. Digging around a bit more in that directory (in particular, in libioP.h and iofopncook.c) reveals that _IO_PBACKFAIL on a FILE created with fopencookie calls _IO_default_pbackfail That function is much longer and I'm not going to quote it, but what it does is allocate a special "backup buffer" and stash the character there. This backup buffer can grow to accomodate an arbitrary number of calls to ungetc if necessary.

So, the answer to your question is that no matter how many times you call ungetc in a row (or other library functions do it for you), your cookie functions will never get asked to do anything. It's all handled internal to the FILE. Per my answer to your other question, I strongly advise that you find some other approach, but for what you were trying to do, I don't see why you think you need to "put this character back to the istream as well."

zwol
  • 135,547
  • 38
  • 252
  • 361
  • The reason I need to get it the character back to istream is, I will mix the call to cstdio functions and iostream functions. If I use istream after scanf, the character held by FILE won't be accessible by istream, therefore lost. Which will be totally wrong. – Kan Li Jun 20 '14 at 03:37
  • Ah. In that case, the answer is: you can't. – zwol Jun 20 '14 at 12:25