]> Git Repo - uclibc-ng.git/blob - libc/stdio/_stdio.c
make sure TARGET_ARCH is set ... thought i committed this already?
[uclibc-ng.git] / libc / stdio / _stdio.c
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 /* This is pretty much straight from uClibc, but with one important
11  * difference.
12  *
13  * We now initialize the locking flag to user locking instead of
14  * auto locking (i.e. FSETLOCKING_BYCALLER vs FSETLOCKING_INTERNAL).
15  * This greatly benefits non-threading applications linked to a
16  * shared thread-enabled library.  In threading applications, we
17  * walk the stdio open file list and reset the locking mode
18  * appropriately when the thread subsystem is initialized.
19  */
20
21 /**********************************************************************/
22
23 #ifdef __UCLIBC_HAS_WCHAR__
24 #define __STDIO_FILE_INIT_WUNGOT                { 0, 0 },
25 #else
26 #define __STDIO_FILE_INIT_WUNGOT
27 #endif
28
29 #ifdef __STDIO_GETC_MACRO
30 # define __STDIO_FILE_INIT_BUFGETC(x) x,
31 #else
32 # define __STDIO_FILE_INIT_BUFGETC(x)
33 #endif
34
35 #ifdef __STDIO_PUTC_MACRO
36 # define __STDIO_FILE_INIT_BUFPUTC(x) x,
37 #else
38 # define __STDIO_FILE_INIT_BUFPUTC(x)
39 #endif
40
41 #ifdef __STDIO_HAS_OPENLIST
42 #define __STDIO_FILE_INIT_NEXT(next)    (next),
43 #else
44 #define __STDIO_FILE_INIT_NEXT(next)
45 #endif
46
47 #ifdef __STDIO_BUFFERS
48 #define __STDIO_FILE_INIT_BUFFERS(buf,bufsize) \
49         (buf), (buf)+(bufsize), (buf), (buf),
50 #else
51 #define __STDIO_FILE_INIT_BUFFERS(buf,bufsize)
52 #endif
53
54 #ifdef __UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__
55 #define __STDIO_FILE_INIT_CUSTOM_STREAM(stream) \
56         &((stream).__filedes), { _cs_read, _cs_write, _cs_seek, _cs_close },
57 #else
58 #define __STDIO_FILE_INIT_CUSTOM_STREAM(stream)
59 #endif
60
61 #ifdef __STDIO_MBSTATE
62 #define __STDIO_FILE_INIT_MBSTATE \
63         { 0, 0 },
64 #else
65 #define __STDIO_FILE_INIT_MBSTATE
66 #endif
67
68 #ifdef __UCLIBC_HAS_XLOCALE__
69 #define __STDIO_FILE_INIT_UNUSED \
70         NULL,
71 #else
72 #define __STDIO_FILE_INIT_UNUSED
73 #endif
74
75 #ifdef __UCLIBC_HAS_THREADS__
76 #define __STDIO_FILE_INIT_THREADSAFE \
77         2, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP,
78 #else
79 #define __STDIO_FILE_INIT_THREADSAFE
80 #endif
81
82 #define __STDIO_INIT_FILE_STRUCT(stream, flags, filedes, next, buf, bufsize) \
83         { (flags), \
84         { 0, 0 }, /* ungot[2] (no wchar) or ungot_width[2] (wchar)*/ \
85         (filedes), \
86         __STDIO_FILE_INIT_BUFFERS(buf,bufsize) \
87         __STDIO_FILE_INIT_BUFGETC((buf)) \
88         __STDIO_FILE_INIT_BUFPUTC((buf)) \
89         __STDIO_FILE_INIT_NEXT(next) \
90         __STDIO_FILE_INIT_CUSTOM_STREAM(stream) \
91         __STDIO_FILE_INIT_WUNGOT \
92         __STDIO_FILE_INIT_MBSTATE \
93         __STDIO_FILE_INIT_UNUSED \
94         __STDIO_FILE_INIT_THREADSAFE \
95 } /* TODO: builtin buf */
96
97 /**********************************************************************/
98 /* First we need the standard files. */
99
100 #ifdef __STDIO_BUFFERS
101 static unsigned char _fixed_buffers[2 * BUFSIZ];
102 #endif
103
104 static FILE _stdio_streams[] = {
105         __STDIO_INIT_FILE_STRUCT(_stdio_streams[0], \
106                                                          __FLAG_LBF|__FLAG_READONLY, \
107                                                          0, \
108                                                          _stdio_streams + 1, \
109                                                          _fixed_buffers, \
110                                                          BUFSIZ ),
111         __STDIO_INIT_FILE_STRUCT(_stdio_streams[1], \
112                                                          __FLAG_LBF|__FLAG_WRITEONLY, \
113                                                          1, \
114                                                          _stdio_streams + 2, \
115                                                          _fixed_buffers + BUFSIZ, \
116                                                          BUFSIZ ),
117         __STDIO_INIT_FILE_STRUCT(_stdio_streams[2], \
118                                                          __FLAG_NBF|__FLAG_WRITEONLY, \
119                                                          2, \
120                                                          NULL, \
121                                                          NULL, \
122                                                          0 )
123 };
124
125 FILE *stdin  = _stdio_streams;
126 FILE *stdout = _stdio_streams + 1;
127 FILE *stderr = _stdio_streams + 2;
128
129 #ifdef __STDIO_GETC_MACRO
130 FILE *__stdin = _stdio_streams;          /* For getchar() macro. */
131 #endif
132 #ifdef __STDIO_PUTC_MACRO
133 FILE *__stdout = _stdio_streams + 1; /* For putchar() macro. */
134 /* FILE *__stderr = _stdio_streams + 2; */
135 #endif
136
137 /**********************************************************************/
138 #ifdef __STDIO_HAS_OPENLIST
139
140 /* In certain configurations, we need to keep a list of open files.
141  * 1) buffering enabled - We need to initialize the buffering mode
142  *       (full or line buffering) of stdin and stdout.  We also
143  *       need to flush all write buffers prior to normal termination.
144  * 2) custom streams - Even if we aren't buffering in the library
145  *       itself, we need to fclose() all custom streams when terminating
146  *       so that any special cleanup is done.
147  * 3) threads enabled - We need to be able to reset the locking mode
148  *       of all open streams when the threading system is initialized.
149  */
150
151 FILE *_stdio_openlist = _stdio_streams;
152
153 # ifdef __UCLIBC_HAS_THREADS__
154 pthread_mutex_t _stdio_openlist_lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
155 int _stdio_openlist_delflag = 0;
156 # endif
157
158 #endif
159 /**********************************************************************/
160 #ifdef __UCLIBC_HAS_THREADS__
161
162 /* 2 if threading not initialized and 0 otherwise; */
163 int _stdio_user_locking = 2;
164
165 void __stdio_init_mutex(pthread_mutex_t *m)
166 {
167         static const pthread_mutex_t __stdio_mutex_initializer
168                 = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
169
170         memcpy(m, &__stdio_mutex_initializer, sizeof(__stdio_mutex_initializer));
171 }
172
173 #endif
174 /**********************************************************************/
175
176 /* We assume here that we are the only remaining thread. */
177 void _stdio_term(void)
178 {
179 #if defined(__STDIO_BUFFERS) || defined(__UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__)
180         register FILE *ptr;
181
182 #ifdef __UCLIBC_HAS_THREADS__
183         /* First, make sure the open file list is unlocked.  If it was
184          * locked, then I suppose there is a chance that a pointer in the
185          * chain might be corrupt due to a partial store.
186          */ 
187         __stdio_init_mutex(&_stdio_openlist_lock);
188
189         /* Next we need to worry about the streams themselves.  If a stream
190          * is currently locked, then it may be in an invalid state.  So we
191          * 'disable' it in case a custom stream is stacked on top of it.
192          * Then we reinitialize the locks.
193          */
194         for (ptr = _stdio_openlist ; ptr ; ptr = ptr->__nextopen ) {
195                 if (__STDIO_ALWAYS_THREADTRYLOCK(ptr)) {
196                         /* The stream is already locked, so we don't want to touch it.
197                          * However, if we have custom streams, we can't just close it
198                          * or leave it locked since a custom stream may be stacked
199                          * on top of it.  So we do unlock it, while also disabling it.
200                          */
201                         ptr->__modeflags = (__FLAG_READONLY|__FLAG_WRITEONLY);
202                         __STDIO_STREAM_DISABLE_GETC(ptr);
203                         __STDIO_STREAM_DISABLE_PUTC(ptr);
204                         __STDIO_STREAM_INIT_BUFREAD_BUFPOS(ptr);
205                 }
206                 
207                 ptr->__user_locking = 1; /* Set locking mode to "by caller". */
208                 __stdio_init_mutex(&ptr->__lock); /* Shouldn't be necessary, but... */
209         }
210 #endif
211
212         /* Finally, flush all writing streams and shut down all custom streams.
213          * NOTE: We assume that any stacking by custom streams is done on top
214          *       of streams previously allocated, and hence further down the
215          *       list.  Otherwise we have no way of knowing the order in which
216          *       to shut them down.
217          *       Remember that freopen() counts as a new allocation here, even
218          *       though the stream is reused.  That's because it moves the
219          *       stream to the head of the list.
220          */
221         for (ptr = _stdio_openlist ; ptr ; ptr = ptr->__nextopen ) {
222 #ifdef __STDIO_BUFFERS
223                 /* Write any pending buffered chars. */
224                 if (__STDIO_STREAM_IS_WRITING(ptr)) {
225                         __STDIO_COMMIT_WRITE_BUFFER(ptr);
226                 }
227 #endif
228 #ifdef __UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__
229                 /* Actually close all custom streams to perform any special cleanup. */
230                 if (ptr->__cookie != &ptr->__filedes) {
231                         __CLOSE(ptr);
232                 }
233 #endif
234         }
235
236 #endif
237 }
238
239 void _stdio_init(void)
240 {
241 #ifdef __STDIO_BUFFERS
242         int old_errno = errno;
243         /* stdin and stdout uses line buffering when connected to a tty. */
244         _stdio_streams[0].__modeflags ^= (1-isatty(0)) * __FLAG_LBF;
245         _stdio_streams[1].__modeflags ^= (1-isatty(1)) * __FLAG_LBF;
246         __set_errno(old_errno);
247 #endif
248 #ifndef __UCLIBC__
249         /* _stdio_term is done automatically when exiting if stdio is used.
250          * See misc/internals/__uClibc_main.c and and stdlib/atexit.c. */
251         atexit(_stdio_term);
252 #endif /* __UCLIBC__ */
253 }
254
255 /**********************************************************************/
256
257 #if !(__MASK_READING & __FLAG_UNGOT)
258 #error Assumption violated about __MASK_READING and __FLAG_UNGOT
259 #endif
260
261 #ifdef __UCLIBC_HAS_THREADS__
262 #include <pthread.h>
263 #endif
264
265 #ifndef NDEBUG
266
267 void _stdio_validate_FILE(const FILE *stream)
268 {
269 #ifdef __UCLIBC_HAS_THREADS__
270         assert(((unsigned int)(stream->__user_locking)) <= 2);
271 #endif
272
273 #warning Define a constant for minimum possible valid __filedes?
274         assert(stream->__filedes >= -3);
275
276         if (stream->__filedes < 0) {
277 /*              assert((stream->__filedes != -1) */
278 /* #ifdef __UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__ */
279 /*                         || (stream->__cookie == &stream->__filedes) /\* custom *\/ */
280 /* #endif */
281 /*                         ); */
282 /*              assert((stream->__filedes == -1) || __STDIO_STREAM_IS_FBF(stream)); */
283
284                 assert(!__STDIO_STREAM_IS_FAKE_VSNPRINTF(stream)
285                            || __STDIO_STREAM_IS_NARROW(stream));
286                 assert(!__STDIO_STREAM_IS_FAKE_VSSCANF(stream)
287                            || __STDIO_STREAM_IS_NARROW(stream));
288 #ifdef __STDIO_STREAM_IS_FAKE_VSWPRINTF
289                 assert(!__STDIO_STREAM_IS_FAKE_VSWPRINTF(stream)
290                            || __STDIO_STREAM_IS_WIDE(stream));
291 #endif
292 #ifdef __STDIO_STREAM_IS_FAKE_VSWSCANF
293                 assert(!__STDIO_STREAM_IS_FAKE_VSWSCANF(stream)
294                            || __STDIO_STREAM_IS_WIDE(stream));
295 #endif
296         }
297
298 #ifdef __UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__
299         if (stream->__cookie != &stream->__filedes) { /* custom */
300                 assert(stream->__filedes == -1);
301         }
302 #endif
303
304         /* Can not be both narrow and wide oriented at the same time. */
305         assert(!(__STDIO_STREAM_IS_NARROW(stream)
306                          && __STDIO_STREAM_IS_WIDE(stream)));
307
308
309         /* The following impossible case is used to disable a stream. */
310         if ((stream->__modeflags & (__FLAG_READONLY|__FLAG_WRITEONLY))
311                 == (__FLAG_READONLY|__FLAG_WRITEONLY)
312                 ) {
313                 assert(stream->__modeflags == (__FLAG_READONLY|__FLAG_WRITEONLY));
314                 assert(stream->__filedes == -1);
315 #ifdef __STDIO_BUFFERS
316                 assert(stream->__bufpos == stream->__bufstart);
317                 assert(stream->__bufread == stream->__bufstart);
318 # ifdef __UCLIBC_HAS_STDIO_PUTC_MACRO__
319                 assert(stream->__bufputc_u == stream->__bufstart);
320 # endif
321 # ifdef __UCLIBC_HAS_STDIO_GETC_MACRO__
322                 assert(stream->__bufgetc_u == stream->__bufstart);
323 # endif
324 #endif
325         }
326
327         if (__STDIO_STREAM_IS_READONLY(stream)) {
328 /*              assert(!__STDIO_STREAM_IS_WRITEONLY(stream)); */
329                 assert(!__STDIO_STREAM_IS_WRITING(stream));
330                 if (stream->__modeflags & __FLAG_UNGOT) {
331                         assert(((unsigned)(stream->__ungot[1])) <= 1);
332                         assert(!__FEOF_UNLOCKED(stream));
333                 }
334         }
335
336         if (__STDIO_STREAM_IS_WRITEONLY(stream)) {
337 /*              assert(!__STDIO_STREAM_IS_READONLY(stream)); */
338                 assert(!__STDIO_STREAM_IS_READING(stream));
339                 assert(!(stream->__modeflags & __FLAG_UNGOT));
340         }
341
342         if (__STDIO_STREAM_IS_NBF(stream)) {
343                 /* We require that all non buffered streams have no buffer. */
344                 assert(!__STDIO_STREAM_BUFFER_SIZE(stream));
345         }
346
347         assert((stream->__modeflags & __MASK_BUFMODE) <= __FLAG_NBF);
348
349 #ifdef __STDIO_BUFFERS
350         /* Ensure __bufstart <= __bufpos <= __bufend. */
351         assert(stream->__bufpos >= stream->__bufstart);
352         assert(stream->__bufpos <= stream->__bufend);
353         /* Ensure __bufstart <= __bufread <= __bufend. */
354         assert(stream->__bufread >= stream->__bufstart);
355         assert(stream->__bufread <= stream->__bufend);
356 #endif
357
358         /* If EOF, then we must have no buffered readable or ungots. */
359         if (__FEOF_UNLOCKED(stream)) {
360 #ifdef __STDIO_BUFFERS
361                 assert(stream->__bufpos == stream->__bufread);
362 #endif
363                 assert(!(stream->__modeflags & __FLAG_UNGOT));
364         }
365
366
367         if (!__STDIO_STREAM_IS_WRITING(stream)) {
368 #ifdef __STDIO_BUFFERS
369                 /* If not writing, then putc macro must be disabled. */
370 # ifdef __UCLIBC_HAS_STDIO_PUTC_MACRO__
371                 assert(stream->__bufputc_u == stream->__bufstart);
372 # endif
373 #endif
374         }
375
376         if (!__STDIO_STREAM_IS_READING(stream)) {
377                 /* If not reading, then can not have ungots. */
378                 assert(!(stream->__modeflags & __FLAG_UNGOT));
379 #ifdef __STDIO_BUFFERS
380                 /* Ensure __bufread == __bufstart. */
381                 assert(stream->__bufread == stream->__bufstart);
382                 /* If not reading, then getc macro must be disabled. */
383 # ifdef __UCLIBC_HAS_STDIO_GETC_MACRO__
384                 assert(stream->__bufgetc_u == stream->__bufstart);
385 # endif
386 #endif
387         }
388
389         if (__STDIO_STREAM_IS_READING(stream)) {
390                 assert(!__STDIO_STREAM_IS_WRITING(stream));
391 #ifdef __STDIO_BUFFERS
392                 /* Ensure __bufpos <= __bufread. */
393                 assert(stream->__bufpos <= stream->__bufread);
394
395                 /* Ensure __bufgetc_u is valid. */
396 # ifdef __UCLIBC_HAS_STDIO_GETC_MACRO__
397                 assert(stream->__bufgetc_u >= stream->__bufstart);
398                 assert(stream->__bufgetc_u <= stream->__bufread);
399 # endif
400
401 #endif
402         }
403
404         if (__STDIO_STREAM_IS_WRITING(stream)) {
405                 assert(!__STDIO_STREAM_IS_READING(stream));
406 #ifdef __STDIO_BUFFERS
407 # ifdef __UCLIBC_HAS_STDIO_PUTC_MACRO__
408                 assert(stream->__bufputc_u >= stream->__bufstart);
409                 assert(stream->__bufputc_u <= stream->__bufend);
410 # endif
411 #endif
412         }
413
414         /* If have an ungotten char, then getc (and putc) must be disabled. */
415         /* Also, wide streams must have the getc/putc macros disabled. */
416         if ((stream->__modeflags & __FLAG_UNGOT)
417                 || __STDIO_STREAM_IS_WIDE(stream)
418                 ) {
419 #ifdef __STDIO_BUFFERS
420 # ifdef __UCLIBC_HAS_STDIO_PUTC_MACRO__
421                 assert(stream->__bufputc_u == stream->__bufstart);
422 # endif
423 # ifdef __UCLIBC_HAS_STDIO_GETC_MACRO__
424                 assert(stream->__bufgetc_u == stream->__bufstart);
425 # endif
426 #endif
427         }
428
429         /* TODO -- filepos?  ungot_width?  filedes?  nextopen? */
430 }
431
432 #endif
This page took 0.048827 seconds and 4 git commands to generate.