OSDN Git Service

hidden_def/hidden_proto: convert all users (I hope) termios split, add some missing...
[uclinux-h8/uClibc.git] / libc / stdio / fflush.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 libc_hidden_proto(fflush_unlocked)
11
12 #ifdef __DO_UNLOCKED
13
14 #ifdef __UCLIBC_MJN3_ONLY__
15 #warning WISHLIST: Add option to test for undefined behavior of fflush.
16 #endif /* __UCLIBC_MJN3_ONLY__ */
17
18 #ifdef __UCLIBC_HAS_THREADS__
19 /* Even if the stream is set to user-locking, we still need to lock
20  * when all (lbf) writing streams are flushed. */
21 #define MY_STDIO_THREADLOCK(STREAM) \
22         if (_stdio_user_locking != 2) { \
23                 __STDIO_ALWAYS_THREADLOCK(STREAM); \
24         }
25
26 #define MY_STDIO_THREADUNLOCK(STREAM) \
27         if (_stdio_user_locking != 2) { \
28                 __STDIO_ALWAYS_THREADUNLOCK(STREAM); \
29         }
30 #else
31 #define MY_STDIO_THREADLOCK(STREAM)             ((void)0)
32 #define MY_STDIO_THREADUNLOCK(STREAM)   ((void)0)
33 #endif
34
35
36 int fflush_unlocked(register FILE *stream)
37 {
38 #ifdef __STDIO_BUFFERS
39
40         int retval = 0;
41 #ifdef __UCLIBC_MJN3_ONLY__
42 #warning REMINDER: should probably define a modeflags type
43 #endif
44         unsigned short bufmask = __FLAG_LBF;
45
46 #ifndef NDEBUG
47         if ((stream != NULL) && (stream != (FILE *) &_stdio_openlist)) {
48                 __STDIO_STREAM_VALIDATE(stream); /* debugging only */
49         }
50 #endif
51
52         if (stream == (FILE *) &_stdio_openlist) { /* Flush all lbf streams. */
53                 stream = NULL;
54                 bufmask = 0;
55         }
56
57         if (!stream) {                          /* Flush all (lbf) writing streams. */
58                 __STDIO_THREADLOCK_OPENLIST;
59                 for (stream = _stdio_openlist; stream ; stream = stream->__nextopen) {
60                         MY_STDIO_THREADLOCK(stream);
61                         if (!(((stream->__modeflags | bufmask)
62                                    ^ (__FLAG_WRITING|__FLAG_LBF)
63                                    ) & (__FLAG_WRITING|__MASK_BUFMODE))
64                                 ) {
65                                 if (!__STDIO_COMMIT_WRITE_BUFFER(stream)) {
66                                         __STDIO_STREAM_DISABLE_PUTC(stream);
67                                         __STDIO_STREAM_CLEAR_WRITING(stream);
68                                 } else {
69                                         retval = EOF;
70                                 }
71                         }
72                         MY_STDIO_THREADUNLOCK(stream);
73                 }
74                 __STDIO_THREADUNLOCK_OPENLIST;
75         } else if (__STDIO_STREAM_IS_WRITING(stream)) {
76                 if (!__STDIO_COMMIT_WRITE_BUFFER(stream)) {
77                         __STDIO_STREAM_DISABLE_PUTC(stream);
78                         __STDIO_STREAM_CLEAR_WRITING(stream);
79                 } else {
80                         retval = EOF;
81                 }
82         }
83 #if 0
84         else if (stream->__modeflags & (__MASK_READING|__FLAG_READONLY)) {
85                 /* ANSI/ISO says behavior in this case is undefined but also says you
86                  * shouldn't flush a stream you were reading from.  As usual, glibc
87                  * caters to broken programs and simply ignores this. */
88                 __UNDEFINED_OR_NONPORTABLE;
89                 __STDIO_STREAM_SET_ERROR(stream);
90                 __set_errno(EBADF);
91                 retval = EOF;
92         }
93 #endif
94
95 #ifndef NDEBUG
96         if ((stream != NULL) && (stream != (FILE *) &_stdio_openlist)) {
97                 __STDIO_STREAM_VALIDATE(stream); /* debugging only */
98         }
99 #endif
100
101         return retval;
102
103 #else  /* __STDIO_BUFFERS --------------------------------------- */
104
105 #ifndef NDEBUG
106         if ((stream != NULL)
107 #ifdef __STDIO_HAS_OPENLIST
108                 && (stream != (FILE *) &_stdio_openlist)
109 #endif
110                 ) {
111                 __STDIO_STREAM_VALIDATE(stream); /* debugging only */
112         }
113 #endif
114
115 #if 0
116         if (stream && (stream->__modeflags & (__MASK_READING|__FLAG_READONLY))) {
117                 /* ANSI/ISO says behavior in this case is undefined but also says you
118                  * shouldn't flush a stream you were reading from.  As usual, glibc
119                  * caters to broken programs and simply ignores this. */
120                 __UNDEFINED_OR_NONPORTABLE;
121                 __STDIO_STREAM_SET_ERROR(stream);
122                 __set_errno(EBADF);
123                 return EOF;
124         }
125 #endif
126
127         return 0;
128 #endif /* __STDIO_BUFFERS */
129 }
130 libc_hidden_def(fflush_unlocked)
131
132 #ifndef __UCLIBC_HAS_THREADS__
133 strong_alias(fflush_unlocked,fflush)
134 libc_hidden_proto(fflush)
135 libc_hidden_def(fflush)
136 #endif
137
138 #elif defined __UCLIBC_HAS_THREADS__
139
140 int fflush(register FILE *stream)
141 {
142         int retval;
143         __STDIO_AUTO_THREADLOCK_VAR;
144
145         if (stream
146 #ifdef __STDIO_HAS_OPENLIST
147                 && (stream != (FILE *) &_stdio_openlist)
148 #endif
149                 ) {
150
151                 __STDIO_AUTO_THREADLOCK(stream);
152
153                 retval = fflush_unlocked(stream);
154
155                 __STDIO_AUTO_THREADUNLOCK(stream);
156         } else {
157                 retval = fflush_unlocked(stream);
158         }
159
160         return retval;
161 }
162 libc_hidden_proto(fflush)
163 libc_hidden_def(fflush)
164
165 #endif