/* Copyright (C) 2004 Manuel Novoa III * * GNU Library General Public License (LGPL) version 2 or later. * * Dedicated to Toni. See uClibc/DEDICATION.mjn3 for details. */ #include "_stdio.h" /* Having ungotten characters implies the stream is reading. * The scheme used here treats the least significant 2 bits of * the stream's modeflags member as follows: * 0 0 Not currently reading. * 0 1 Reading, but no ungetc() or scanf() push back chars. * 1 0 Reading with one ungetc() char (ungot[1] is 1) * or one scanf() pushed back char (ungot[1] is 0). * 1 1 Reading with both an ungetc() char and a scanf() * pushed back char. Note that this must be the result * of a scanf() push back (in ungot[0]) _followed_ by * an ungetc() call (in ungot[1]). * * Notes: * scanf() can NOT use ungetc() to push back characters. * (See section 7.19.6.2 of the C9X rationale -- WG14/N897.) */ int ungetc(int c, register FILE *stream) { __STDIO_AUTO_THREADLOCK_VAR; __STDIO_AUTO_THREADLOCK(stream); __STDIO_STREAM_VALIDATE(stream); #ifdef __UCLIBC_MJN3_ONLY__ #warning CONSIDER: Make fast ungetc an option? #endif #ifdef __UCLIBC_HAS_STDIO_GETC_MACRO__ /* If buffered narrow reading with no ungot slots filled, and if not * ungetting a different char than the one last read from the buffer, * we can simply decrement the position and not worry about disabling * the getc macros. This will cut down on overhead in applications * that use getc/ungetc extensively (like gcc). */ /* NOTE: If we can use getc, then we are buffered narrow reading with * no ungot slots filled. */ if (__STDIO_STREAM_CAN_USE_BUFFER_GET(stream) && (c != EOF) && (stream->__bufpos > stream->__bufstart) && (stream->__bufpos[-1] == ((unsigned char)c)) ) { --stream->__bufpos; __STDIO_STREAM_CLEAR_EOF(stream); /* Must clear end-of-file flag. */ } else #endif /* Note: Even if c == EOF, we need to initialize/verify the * stream's orientation and ensure the stream is in reading * mode (if readable and properly oriented). */ if ((!__STDIO_STREAM_IS_NARROW_READING(stream) && __STDIO_STREAM_TRANS_TO_READ(stream, __FLAG_NARROW)) || ((stream->__modeflags & __FLAG_UNGOT) && ((stream->__modeflags & 1) || stream->__ungot[1])) ) { c = EOF; } else if (c != EOF) { __STDIO_STREAM_DISABLE_GETC(stream); /* Flag this as a user ungot, as scanf does the necessary fixup. */ stream->__ungot[1] = 1; stream->__ungot[(++stream->__modeflags) & 1] = c; __STDIO_STREAM_CLEAR_EOF(stream); /* Must clear end-of-file flag. */ } __STDIO_STREAM_VALIDATE(stream); __STDIO_AUTO_THREADUNLOCK(stream); return c; } libc_hidden_def(ungetc)