OSDN Git Service

ARC: Make vfork weak in libc
[uclinux-h8/uClibc.git] / libc / stdio / ungetc.c
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)