lh | 9ed821d | 2023-04-07 01:36:19 -0700 | [diff] [blame^] | 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 | |
| 27 | int 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) |