source: trunk/libs/newlib/src/newlib/libc/stdio/findfp.c @ 471

Last change on this file since 471 was 444, checked in by satin@…, 6 years ago

add newlib,libalmos-mkh, restructure shared_syscalls.h and mini-libc

File size: 8.1 KB
Line 
1/*
2 * Copyright (c) 1990 The Regents of the University of California.
3 * All rights reserved.
4 *
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 * advertising materials, and 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.
16 */
17/* No user fns here.  Pesch 15apr92. */
18
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"
28
29#ifdef _REENT_SMALL
30const struct __sFILE_fake __sf_fake_stdin =
31    {_NULL, 0, 0, 0, 0, {_NULL, 0}, 0, _NULL};
32const struct __sFILE_fake __sf_fake_stdout =
33    {_NULL, 0, 0, 0, 0, {_NULL, 0}, 0, _NULL};
34const struct __sFILE_fake __sf_fake_stderr =
35    {_NULL, 0, 0, 0, 0, {_NULL, 0}, 0, _NULL};
36#endif
37
38#ifdef _REENT_GLOBAL_STDIO_STREAMS
39__FILE __sf[3];
40#endif
41
42#if (defined (__OPTIMIZE_SIZE__) || defined (PREFER_SIZE_OVER_SPEED))
43_NOINLINE_STATIC void
44#else
45static void
46#endif
47std (FILE *ptr,
48            int flags,
49            int file)
50{
51  ptr->_p = 0;
52  ptr->_r = 0;
53  ptr->_w = 0;
54  ptr->_flags = flags;
55  ptr->_flags2 = 0;
56  ptr->_file = file;
57  ptr->_bf._base = 0;
58  ptr->_bf._size = 0;
59  ptr->_lbfsize = 0;
60  memset (&ptr->_mbstate, 0, sizeof (_mbstate_t));
61  ptr->_cookie = ptr;
62  ptr->_read = __sread;
63#ifndef __LARGE64_FILES
64  ptr->_write = __swrite;
65#else /* __LARGE64_FILES */
66  ptr->_write = __swrite64;
67  ptr->_seek64 = __sseek64;
68  ptr->_flags |= __SL64;
69#endif /* __LARGE64_FILES */
70  ptr->_seek = __sseek;
71#ifdef _STDIO_CLOSE_PER_REENT_STD_STREAMS
72  ptr->_close = __sclose;
73#else /* _STDIO_CLOSE_STD_STREAMS */
74  ptr->_close = NULL;
75#endif /* _STDIO_CLOSE_STD_STREAMS */
76#if !defined(__SINGLE_THREAD__) && !defined(_REENT_SMALL)
77  __lock_init_recursive (ptr->_lock);
78  /*
79   * #else
80   * lock is already initialized in __sfp
81   */
82#endif
83
84#ifdef __SCLE
85  if (__stextmode (ptr->_file))
86    ptr->_flags |= __SCLE;
87#endif
88}
89
90static inline void
91stdin_init(FILE *ptr)
92{
93  std (ptr,  __SRD, 0);
94}
95
96static inline void
97stdout_init(FILE *ptr)
98{
99  /* On platforms that have true file system I/O, we can verify
100     whether stdout is an interactive terminal or not, as part of
101     __smakebuf on first use of the stream.  For all other platforms,
102     we will default to line buffered mode here.  Technically, POSIX
103     requires both stdin and stdout to be line-buffered, but tradition
104     leaves stdin alone on systems without fcntl.  */
105#ifdef HAVE_FCNTL
106  std (ptr, __SWR, 1);
107#else
108  std (ptr, __SWR | __SLBF, 1);
109#endif
110}
111
112static inline void
113stderr_init(FILE *ptr)
114{
115  /* POSIX requires stderr to be opened for reading and writing, even
116     when the underlying fd 2 is write-only.  */
117  std (ptr, __SRW | __SNBF, 2);
118}
119
120struct glue_with_file {
121  struct _glue glue;
122  FILE file;
123};
124
125struct _glue *
126__sfmoreglue (struct _reent *d,
127       register int n)
128{
129  struct glue_with_file *g;
130
131  g = (struct glue_with_file *)
132    _malloc_r (d, sizeof (*g) + (n - 1) * sizeof (FILE));
133  if (g == NULL)
134    return NULL;
135  g->glue._next = NULL;
136  g->glue._niobs = n;
137  g->glue._iobs = &g->file;
138  memset (&g->file, 0, n * sizeof (FILE));
139  return &g->glue;
140}
141
142/*
143 * Find a free FILE for fopen et al.
144 */
145
146FILE *
147__sfp (struct _reent *d)
148{
149  FILE *fp;
150  int n;
151  struct _glue *g;
152
153  _newlib_sfp_lock_start ();
154
155  if (!_GLOBAL_REENT->__sdidinit)
156    __sinit (_GLOBAL_REENT);
157  for (g = &_GLOBAL_REENT->__sglue;; g = g->_next)
158    {
159      for (fp = g->_iobs, n = g->_niobs; --n >= 0; fp++)
160        if (fp->_flags == 0)
161          goto found;
162      if (g->_next == NULL &&
163          (g->_next = __sfmoreglue (d, NDYNAMIC)) == NULL)
164        break;
165    }
166  _newlib_sfp_lock_exit ();
167  d->_errno = ENOMEM;
168  return NULL;
169
170found:
171  fp->_file = -1;               /* no file */
172  fp->_flags = 1;               /* reserve this slot; caller sets real flags */
173  fp->_flags2 = 0;
174#ifndef __SINGLE_THREAD__
175  __lock_init_recursive (fp->_lock);
176#endif
177  _newlib_sfp_lock_end ();
178
179  fp->_p = NULL;                /* no current pointer */
180  fp->_w = 0;                   /* nothing to read or write */
181  fp->_r = 0;
182  fp->_bf._base = NULL;         /* no buffer */
183  fp->_bf._size = 0;
184  fp->_lbfsize = 0;             /* not line buffered */
185  memset (&fp->_mbstate, 0, sizeof (_mbstate_t));
186  /* fp->_cookie = <any>; */    /* caller sets cookie, _read/_write etc */
187  fp->_ub._base = NULL;         /* no ungetc buffer */
188  fp->_ub._size = 0;
189  fp->_lb._base = NULL;         /* no line buffer */
190  fp->_lb._size = 0;
191
192  return fp;
193}
194
195/*
196 * exit() calls _cleanup() through *__cleanup, set whenever we
197 * open or buffer a file.  This chicanery is done so that programs
198 * that do not use stdio need not link it all in.
199 *
200 * The name `_cleanup' is, alas, fairly well known outside stdio.
201 */
202
203void
204_cleanup_r (struct _reent *ptr)
205{
206  int (*cleanup_func) (struct _reent *, FILE *);
207#ifdef _STDIO_BSD_SEMANTICS
208  /* BSD and Glibc systems only flush streams which have been written to
209     at exit time.  Calling flush rather than close for speed, as on
210     the aforementioned systems. */
211  cleanup_func = __sflushw_r;
212#else
213  /* Otherwise close files and flush read streams, too.
214     Note we call flush directly if "--enable-lite-exit" is in effect.  */
215#ifdef _LITE_EXIT
216  cleanup_func = _fflush_r;
217#else
218  cleanup_func = _fclose_r;
219#endif
220#endif
221#ifdef _REENT_GLOBAL_STDIO_STREAMS
222  if (ptr->_stdin != &__sf[0])
223    (*cleanup_func) (ptr, ptr->_stdin);
224  if (ptr->_stdout != &__sf[1])
225    (*cleanup_func) (ptr, ptr->_stdout);
226  if (ptr->_stderr != &__sf[2])
227    (*cleanup_func) (ptr, ptr->_stderr);
228#endif
229  (void) _fwalk_reent (ptr, cleanup_func);
230}
231
232#ifndef _REENT_ONLY
233void
234_cleanup (void)
235{
236  _cleanup_r (_GLOBAL_REENT);
237}
238#endif
239
240/*
241 * __sinit() is called whenever stdio's internal variables must be set up.
242 */
243
244void
245__sinit (struct _reent *s)
246{
247  __sinit_lock_acquire ();
248
249  if (s->__sdidinit)
250    {
251      __sinit_lock_release ();
252      return;
253    }
254
255  /* make sure we clean up on exit */
256  s->__cleanup = _cleanup_r;    /* conservative */
257
258  s->__sglue._next = NULL;
259#ifndef _REENT_SMALL
260# ifndef _REENT_GLOBAL_STDIO_STREAMS
261  s->__sglue._niobs = 3;
262  s->__sglue._iobs = &s->__sf[0];
263# endif
264#else
265  s->__sglue._niobs = 0;
266  s->__sglue._iobs = NULL;
267  /* Avoid infinite recursion when calling __sfp  for _GLOBAL_REENT.  The
268     problem is that __sfp checks for _GLOBAL_REENT->__sdidinit and calls
269     __sinit if it's 0. */
270  if (s == _GLOBAL_REENT)
271    s->__sdidinit = 1;
272  s->_stdin = __sfp(s);
273  s->_stdout = __sfp(s);
274  s->_stderr = __sfp(s);
275#endif
276
277#ifdef _REENT_GLOBAL_STDIO_STREAMS
278  if (__sf[0]._cookie == NULL) {
279    _GLOBAL_REENT->__sglue._niobs = 3;
280    _GLOBAL_REENT->__sglue._iobs = &__sf[0];
281    stdin_init (&__sf[0]);
282    stdout_init (&__sf[1]);
283    stderr_init (&__sf[2]);
284  }
285#else
286  stdin_init (s->_stdin);
287  stdout_init (s->_stdout);
288  stderr_init (s->_stderr);
289#endif
290
291  s->__sdidinit = 1;
292
293  __sinit_lock_release ();
294}
295
296#ifndef __SINGLE_THREAD__
297
298__LOCK_INIT_RECURSIVE(static, __sfp_recursive_mutex);
299__LOCK_INIT_RECURSIVE(static, __sinit_recursive_mutex);
300
301void
302__sfp_lock_acquire (void)
303{
304  __lock_acquire_recursive (__sfp_recursive_mutex);
305}
306
307void
308__sfp_lock_release (void)
309{
310  __lock_release_recursive (__sfp_recursive_mutex);
311}
312
313void
314__sinit_lock_acquire (void)
315{
316  __lock_acquire_recursive (__sinit_recursive_mutex);
317}
318
319void
320__sinit_lock_release (void)
321{
322  __lock_release_recursive (__sinit_recursive_mutex);
323}
324
325/* Walkable file locking routine.  */
326static int
327__fp_lock (FILE * ptr)
328{
329  if (!(ptr->_flags2 & __SNLK))
330    _flockfile (ptr);
331
332  return 0;
333}
334
335/* Walkable file unlocking routine.  */
336static int
337__fp_unlock (FILE * ptr)
338{
339  if (!(ptr->_flags2 & __SNLK))
340    _funlockfile (ptr);
341
342  return 0;
343}
344
345void
346__fp_lock_all (void)
347{
348  __sfp_lock_acquire ();
349
350  (void) _fwalk (_REENT, __fp_lock);
351}
352
353void
354__fp_unlock_all (void)
355{
356  (void) _fwalk (_REENT, __fp_unlock);
357
358  __sfp_lock_release ();
359}
360#endif
Note: See TracBrowser for help on using the repository browser.