]>
Commit | Line | Data |
---|---|---|
082e680b MNI |
1 | /* Copyright (C) 2004 Manuel Novoa III <[email protected]> |
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 | } |