Cygwin: mmap: allow remapping part of an existing anonymous mapping
[newlib-cygwin.git] / newlib / libc / stdio / findfp.c
blob2cc549537f1bd7d109a3223e8c56598b66b4436b
1 /*
2 * Copyright (c) 1990 The Regents of the University of California.
3 * All rights reserved.
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. */
19 #include <_ansi.h>
20 #include <reent.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <errno.h>
24 #include <string.h>
25 #include <fcntl.h>
26 #include <sys/lock.h>
27 #include "local.h"
29 void (*__stdio_exit_handler) (void);
31 __FILE __sf[3];
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 *);
40 #endif
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
47 #else
48 /* Otherwise close files and flush read streams, too.
49 Note we call flush directly if "--enable-lite-exit" is in effect. */
50 #ifdef _LITE_EXIT
51 #define CLEANUP_FILE _fflush_r
52 #else
53 #define CLEANUP_FILE _fclose_r
54 #endif
55 #endif
57 #if (defined (__OPTIMIZE_SIZE__) || defined (PREFER_SIZE_OVER_SPEED))
58 _NOINLINE_STATIC void
59 #else
60 static void
61 #endif
62 std (FILE *ptr,
63 int flags,
64 int file)
66 ptr->_p = 0;
67 ptr->_r = 0;
68 ptr->_w = 0;
69 ptr->_flags = flags;
70 ptr->_flags2 = 0;
71 ptr->_file = file;
72 ptr->_bf._base = 0;
73 ptr->_bf._size = 0;
74 ptr->_lbfsize = 0;
75 memset (&ptr->_mbstate, 0, sizeof (_mbstate_t));
76 ptr->_cookie = ptr;
77 ptr->_read = __sread;
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 */
85 ptr->_seek = __sseek;
86 #ifdef _STDIO_CLOSE_PER_REENT_STD_STREAMS
87 ptr->_close = __sclose;
88 #else /* _STDIO_CLOSE_STD_STREAMS */
89 ptr->_close = NULL;
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);
94 #endif
95 #ifdef __SCLE
96 if (__stextmode (ptr->_file))
97 ptr->_flags |= __SCLE;
98 #endif
101 static inline void
102 stdin_init(FILE *ptr)
104 std (ptr, __SRD, 0);
107 static inline void
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. */
116 #ifdef HAVE_FCNTL
117 std (ptr, __SWR, 1);
118 #else
119 std (ptr, __SWR | __SLBF, 1);
120 #endif
123 static inline void
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 {
132 struct _glue glue;
133 FILE 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));
143 if (g == NULL)
144 return NULL;
145 g->glue._next = NULL;
146 g->glue._niobs = n;
147 g->glue._iobs = &g->file;
148 memset (&g->file, 0, n * sizeof (FILE));
149 return &g->glue;
152 static void
153 stdio_exit_handler (void)
155 (void) _fwalk_sglue (_GLOBAL_REENT, CLEANUP_FILE, &__sglue);
158 static void
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.
173 FILE *
174 __sfp (struct _reent *d)
176 FILE *fp;
177 int n;
178 struct _glue *g;
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++)
186 if (fp->_flags == 0)
187 goto found;
188 if (g->_next == NULL &&
189 (g->_next = sfmoreglue (d, NDYNAMIC)) == NULL)
190 break;
192 _newlib_sfp_lock_exit ();
193 _REENT_ERRNO(d) = ENOMEM;
194 return NULL;
196 found:
197 fp->_file = -1; /* no file */
198 fp->_flags = 1; /* reserve this slot; caller sets real flags */
199 fp->_flags2 = 0;
200 #ifndef __SINGLE_THREAD__
201 __lock_init_recursive (fp->_lock);
202 #endif
203 _newlib_sfp_lock_end ();
205 fp->_p = NULL; /* no current pointer */
206 fp->_w = 0; /* nothing to read or write */
207 fp->_r = 0;
208 fp->_bf._base = NULL; /* no buffer */
209 fp->_bf._size = 0;
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 */
214 fp->_ub._size = 0;
215 fp->_lb._base = NULL; /* no line buffer */
216 fp->_lb._size = 0;
218 return fp;
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.
229 static void
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.
244 void
245 __sinit (struct _reent *s)
247 __sfp_lock_acquire ();
249 if (_REENT_CLEANUP(s))
251 __sfp_lock_release ();
252 return;
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);
266 void
267 __sfp_lock_acquire (void)
269 __lock_acquire_recursive (__sfp_recursive_mutex);
272 void
273 __sfp_lock_release (void)
275 __lock_release_recursive (__sfp_recursive_mutex);
278 /* Walkable file locking routine. */
279 static int
280 __fp_lock (struct _reent * ptr __unused, FILE * fp)
282 if (!(fp->_flags2 & __SNLK))
283 _flockfile (fp);
285 return 0;
288 /* Walkable file unlocking routine. */
289 static int
290 __fp_unlock (struct _reent * ptr __unused, FILE * fp)
292 if (!(fp->_flags2 & __SNLK))
293 _funlockfile (fp);
295 return 0;
298 void
299 __fp_lock_all (void)
301 __sfp_lock_acquire ();
302 (void) _fwalk_sglue (NULL, __fp_lock, &__sglue);
305 void
306 __fp_unlock_all (void)
308 (void) _fwalk_sglue (NULL, __fp_unlock, &__sglue);
309 __sfp_lock_release ();
311 #endif