2 * Copyright (c) 1990 The Regents of the University of California.
5 * Redistribution and use in source and binary forms are permitted
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * and/or other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley. The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
17 /* No user fns here. Pesch 15apr92. */
29 void (*__stdio_exit_handler
) (void);
33 struct _glue __sglue
= {NULL
, 3, &__sf
[0]};
35 #ifdef _REENT_THREAD_LOCAL
36 _Thread_local __FILE
*_tls_stdin
= &__sf
[0];
37 _Thread_local __FILE
*_tls_stdout
= &__sf
[1];
38 _Thread_local __FILE
*_tls_stderr
= &__sf
[2];
39 _Thread_local
void (*_tls_cleanup
)(struct _reent
*);
42 #ifdef _STDIO_BSD_SEMANTICS
43 /* BSD and Glibc systems only flush streams which have been written to
44 at exit time. Calling flush rather than close for speed, as on
45 the aforementioned systems. */
46 #define CLEANUP_FILE __sflushw_r
48 /* Otherwise close files and flush read streams, too.
49 Note we call flush directly if "--enable-lite-exit" is in effect. */
51 #define CLEANUP_FILE _fflush_r
53 #define CLEANUP_FILE _fclose_r
57 #if (defined (__OPTIMIZE_SIZE__) || defined (PREFER_SIZE_OVER_SPEED))
75 memset (&ptr
->_mbstate
, 0, sizeof (_mbstate_t
));
78 #ifndef __LARGE64_FILES
79 ptr
->_write
= __swrite
;
80 #else /* __LARGE64_FILES */
81 ptr
->_write
= __swrite64
;
82 ptr
->_seek64
= __sseek64
;
83 ptr
->_flags
|= __SL64
;
84 #endif /* __LARGE64_FILES */
86 #ifdef _STDIO_CLOSE_PER_REENT_STD_STREAMS
87 ptr
->_close
= __sclose
;
88 #else /* _STDIO_CLOSE_STD_STREAMS */
90 #endif /* _STDIO_CLOSE_STD_STREAMS */
91 #ifndef __SINGLE_THREAD__
92 if (ptr
== &__sf
[0] || ptr
== &__sf
[1] || ptr
== &__sf
[2])
93 __lock_init_recursive (ptr
->_lock
);
96 if (__stextmode (ptr
->_file
))
97 ptr
->_flags
|= __SCLE
;
102 stdin_init(FILE *ptr
)
108 stdout_init(FILE *ptr
)
110 /* On platforms that have true file system I/O, we can verify
111 whether stdout is an interactive terminal or not, as part of
112 __smakebuf on first use of the stream. For all other platforms,
113 we will default to line buffered mode here. Technically, POSIX
114 requires both stdin and stdout to be line-buffered, but tradition
115 leaves stdin alone on systems without fcntl. */
119 std (ptr
, __SWR
| __SLBF
, 1);
124 stderr_init(FILE *ptr
)
126 /* POSIX requires stderr to be opened for reading and writing, even
127 when the underlying fd 2 is write-only. */
128 std (ptr
, __SRW
| __SNBF
, 2);
131 struct glue_with_file
{
136 static struct _glue
*
137 sfmoreglue (struct _reent
*d
, int n
)
139 struct glue_with_file
*g
;
141 g
= (struct glue_with_file
*)
142 _malloc_r (d
, sizeof (*g
) + (n
- 1) * sizeof (FILE));
145 g
->glue
._next
= NULL
;
147 g
->glue
._iobs
= &g
->file
;
148 memset (&g
->file
, 0, n
* sizeof (FILE));
153 stdio_exit_handler (void)
155 (void) _fwalk_sglue (_GLOBAL_REENT
, CLEANUP_FILE
, &__sglue
);
159 global_stdio_init (void)
161 if (__stdio_exit_handler
== NULL
) {
162 __stdio_exit_handler
= stdio_exit_handler
;
163 stdin_init (&__sf
[0]);
164 stdout_init (&__sf
[1]);
165 stderr_init (&__sf
[2]);
170 * Find a free FILE for fopen et al.
174 __sfp (struct _reent
*d
)
180 _newlib_sfp_lock_start ();
181 global_stdio_init ();
183 for (g
= &__sglue
;; g
= g
->_next
)
185 for (fp
= g
->_iobs
, n
= g
->_niobs
; --n
>= 0; fp
++)
188 if (g
->_next
== NULL
&&
189 (g
->_next
= sfmoreglue (d
, NDYNAMIC
)) == NULL
)
192 _newlib_sfp_lock_exit ();
193 _REENT_ERRNO(d
) = ENOMEM
;
197 fp
->_file
= -1; /* no file */
198 fp
->_flags
= 1; /* reserve this slot; caller sets real flags */
200 #ifndef __SINGLE_THREAD__
201 __lock_init_recursive (fp
->_lock
);
203 _newlib_sfp_lock_end ();
205 fp
->_p
= NULL
; /* no current pointer */
206 fp
->_w
= 0; /* nothing to read or write */
208 fp
->_bf
._base
= NULL
; /* no buffer */
210 fp
->_lbfsize
= 0; /* not line buffered */
211 memset (&fp
->_mbstate
, 0, sizeof (_mbstate_t
));
212 /* fp->_cookie = <any>; */ /* caller sets cookie, _read/_write etc */
213 fp
->_ub
._base
= NULL
; /* no ungetc buffer */
215 fp
->_lb
._base
= NULL
; /* no line buffer */
222 * exit() calls _cleanup() through *__cleanup, set whenever we
223 * open or buffer a file. This chicanery is done so that programs
224 * that do not use stdio need not link it all in.
226 * The name `_cleanup' is, alas, fairly well known outside stdio.
230 cleanup_stdio (struct _reent
*ptr
)
232 if (_REENT_STDIN(ptr
) != &__sf
[0])
233 CLEANUP_FILE (ptr
, _REENT_STDIN(ptr
));
234 if (_REENT_STDOUT(ptr
) != &__sf
[1])
235 CLEANUP_FILE (ptr
, _REENT_STDOUT(ptr
));
236 if (_REENT_STDERR(ptr
) != &__sf
[2])
237 CLEANUP_FILE (ptr
, _REENT_STDERR(ptr
));
241 * __sinit() is called whenever stdio's internal variables must be set up.
245 __sinit (struct _reent
*s
)
247 __sfp_lock_acquire ();
249 if (_REENT_CLEANUP(s
))
251 __sfp_lock_release ();
255 /* make sure we clean up on exit */
256 _REENT_CLEANUP(s
) = cleanup_stdio
; /* conservative */
258 global_stdio_init ();
259 __sfp_lock_release ();
262 #ifndef __SINGLE_THREAD__
264 __LOCK_INIT_RECURSIVE(static, __sfp_recursive_mutex
);
267 __sfp_lock_acquire (void)
269 __lock_acquire_recursive (__sfp_recursive_mutex
);
273 __sfp_lock_release (void)
275 __lock_release_recursive (__sfp_recursive_mutex
);
278 /* Walkable file locking routine. */
280 __fp_lock (struct _reent
* ptr __unused
, FILE * fp
)
282 if (!(fp
->_flags2
& __SNLK
))
288 /* Walkable file unlocking routine. */
290 __fp_unlock (struct _reent
* ptr __unused
, FILE * fp
)
292 if (!(fp
->_flags2
& __SNLK
))
301 __sfp_lock_acquire ();
302 (void) _fwalk_sglue (NULL
, __fp_lock
, &__sglue
);
306 __fp_unlock_all (void)
308 (void) _fwalk_sglue (NULL
, __fp_unlock
, &__sglue
);
309 __sfp_lock_release ();