diff options
Diffstat (limited to 'libc/stdio/ungetc.c')
-rw-r--r-- | libc/stdio/ungetc.c | 77 |
1 files changed, 77 insertions, 0 deletions
diff --git a/libc/stdio/ungetc.c b/libc/stdio/ungetc.c new file mode 100644 index 000000000..1b9197a18 --- /dev/null +++ b/libc/stdio/ungetc.c @@ -0,0 +1,77 @@ +/* Copyright (C) 2004 Manuel Novoa III <mjn3@codepoet.org> + * + * 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; +} |