1 /* Copyright (C) 2004 Manuel Novoa III <mjn3@codepoet.org> 2 * 3 * GNU Library General Public License (LGPL) version 2 or later. 4 * 5 * Dedicated to Toni. See uClibc/DEDICATION.mjn3 for details. 6 */ 7 8 #include "_stdio.h" 9 10 /* Having ungotten characters implies the stream is reading. 11 * The scheme used here treats the least significant 2 bits of 12 * the stream's modeflags member as follows: 13 * 0 0 Not currently reading. 14 * 0 1 Reading, but no ungetc() or scanf() push back chars. 15 * 1 0 Reading with one ungetc() char (ungot[1] is 1) 16 * or one scanf() pushed back char (ungot[1] is 0). 17 * 1 1 Reading with both an ungetc() char and a scanf() 18 * pushed back char. Note that this must be the result 19 * of a scanf() push back (in ungot[0]) _followed_ by 20 * an ungetc() call (in ungot[1]). 21 * 22 * Notes: 23 * scanf() can NOT use ungetc() to push back characters. 24 * (See section 7.19.6.2 of the C9X rationale -- WG14/N897.) 25 */ 26 ungetc(int c,register FILE * stream)27int ungetc(int c, register FILE *stream) 28 { 29 __STDIO_AUTO_THREADLOCK_VAR; 30 31 __STDIO_AUTO_THREADLOCK(stream); 32 __STDIO_STREAM_VALIDATE(stream); 33 34 #ifdef __UCLIBC_MJN3_ONLY__ 35 #warning CONSIDER: Make fast ungetc an option? 36 #endif 37 #ifdef __UCLIBC_HAS_STDIO_GETC_MACRO__ 38 /* If buffered narrow reading with no ungot slots filled, and if not 39 * ungetting a different char than the one last read from the buffer, 40 * we can simply decrement the position and not worry about disabling 41 * the getc macros. This will cut down on overhead in applications 42 * that use getc/ungetc extensively (like gcc). */ 43 /* NOTE: If we can use getc, then we are buffered narrow reading with 44 * no ungot slots filled. */ 45 if (__STDIO_STREAM_CAN_USE_BUFFER_GET(stream) 46 && (c != EOF) 47 && (stream->__bufpos > stream->__bufstart) 48 && (stream->__bufpos[-1] == ((unsigned char)c)) 49 ) { 50 --stream->__bufpos; 51 __STDIO_STREAM_CLEAR_EOF(stream); /* Must clear end-of-file flag. */ 52 } else 53 #endif 54 /* Note: Even if c == EOF, we need to initialize/verify the 55 * stream's orientation and ensure the stream is in reading 56 * mode (if readable and properly oriented). */ 57 if ((!__STDIO_STREAM_IS_NARROW_READING(stream) 58 && __STDIO_STREAM_TRANS_TO_READ(stream, __FLAG_NARROW)) 59 || ((stream->__modeflags & __FLAG_UNGOT) 60 && ((stream->__modeflags & 1) || stream->__ungot[1])) 61 ) { 62 c = EOF; 63 } else if (c != EOF) { 64 __STDIO_STREAM_DISABLE_GETC(stream); 65 66 /* Flag this as a user ungot, as scanf does the necessary fixup. */ 67 stream->__ungot[1] = 1; 68 stream->__ungot[(++stream->__modeflags) & 1] = c; 69 70 __STDIO_STREAM_CLEAR_EOF(stream); /* Must clear end-of-file flag. */ 71 } 72 73 __STDIO_STREAM_VALIDATE(stream); 74 __STDIO_AUTO_THREADUNLOCK(stream); 75 76 return c; 77 } 78 libc_hidden_def(ungetc) 79