0,0 → 1,294 |
/* |
* Copyright (c) 1990 The Regents of the University of California. |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms are permitted |
* provided that the above copyright notice and this paragraph are |
* duplicated in all such forms and that any documentation, |
* advertising materials, and other materials related to such |
* distribution and use acknowledge that the software was developed |
* by the University of California, Berkeley. The name of the |
* University may not be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED |
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
*/ |
/* No user fns here. Pesch 15apr92. */ |
|
#include <_ansi.h> |
#include <reent.h> |
#include <stdio.h> |
#include <stdlib.h> |
#include <errno.h> |
#include <string.h> |
#include <fcntl.h> |
#include <sys/lock.h> |
#include "local.h" |
|
#ifdef _REENT_SMALL |
const struct __sFILE_fake __sf_fake_stdin = |
{_NULL, 0, 0, 0, 0, {_NULL, 0}, 0, _NULL}; |
const struct __sFILE_fake __sf_fake_stdout = |
{_NULL, 0, 0, 0, 0, {_NULL, 0}, 0, _NULL}; |
const struct __sFILE_fake __sf_fake_stderr = |
{_NULL, 0, 0, 0, 0, {_NULL, 0}, 0, _NULL}; |
#endif |
|
static _VOID |
_DEFUN(std, (ptr, flags, file, data), |
FILE *ptr _AND |
int flags _AND |
int file _AND |
struct _reent *data) |
{ |
ptr->_p = 0; |
ptr->_r = 0; |
ptr->_w = 0; |
ptr->_flags = flags; |
ptr->_flags2 = 0; |
ptr->_file = file; |
ptr->_bf._base = 0; |
ptr->_bf._size = 0; |
ptr->_lbfsize = 0; |
memset (&ptr->_mbstate, 0, sizeof (_mbstate_t)); |
ptr->_cookie = ptr; |
ptr->_read = __sread; |
#ifndef __LARGE64_FILES |
ptr->_write = __swrite; |
#else /* __LARGE64_FILES */ |
ptr->_write = __swrite64; |
ptr->_seek64 = __sseek64; |
ptr->_flags |= __SL64; |
#endif /* __LARGE64_FILES */ |
ptr->_seek = __sseek; |
ptr->_close = __sclose; |
#if !defined(__SINGLE_THREAD__) && !defined(_REENT_SMALL) |
__lock_init_recursive (ptr->_lock); |
/* |
* #else |
* lock is already initialized in __sfp |
*/ |
#endif |
|
#ifdef __SCLE |
if (__stextmode (ptr->_file)) |
ptr->_flags |= __SCLE; |
#endif |
} |
|
struct _glue * |
_DEFUN(__sfmoreglue, (d, n), |
struct _reent *d _AND |
register int n) |
{ |
struct _glue *g; |
FILE *p; |
|
g = (struct _glue *) _malloc_r (d, sizeof (*g) + n * sizeof (FILE)); |
if (g == NULL) |
return NULL; |
p = (FILE *) (g + 1); |
g->_next = NULL; |
g->_niobs = n; |
g->_iobs = p; |
memset (p, 0, n * sizeof (FILE)); |
return g; |
} |
|
/* |
* Find a free FILE for fopen et al. |
*/ |
|
FILE * |
_DEFUN(__sfp, (d), |
struct _reent *d) |
{ |
FILE *fp; |
int n; |
struct _glue *g; |
|
__sfp_lock_acquire (); |
|
if (!_GLOBAL_REENT->__sdidinit) |
__sinit (_GLOBAL_REENT); |
for (g = &_GLOBAL_REENT->__sglue;; g = g->_next) |
{ |
for (fp = g->_iobs, n = g->_niobs; --n >= 0; fp++) |
if (fp->_flags == 0) |
goto found; |
if (g->_next == NULL && |
(g->_next = __sfmoreglue (d, NDYNAMIC)) == NULL) |
break; |
} |
__sfp_lock_release (); |
d->_errno = ENOMEM; |
return NULL; |
|
found: |
fp->_file = -1; /* no file */ |
fp->_flags = 1; /* reserve this slot; caller sets real flags */ |
fp->_flags2 = 0; |
#ifndef __SINGLE_THREAD__ |
__lock_init_recursive (fp->_lock); |
#endif |
__sfp_lock_release (); |
|
fp->_p = NULL; /* no current pointer */ |
fp->_w = 0; /* nothing to read or write */ |
fp->_r = 0; |
fp->_bf._base = NULL; /* no buffer */ |
fp->_bf._size = 0; |
fp->_lbfsize = 0; /* not line buffered */ |
memset (&fp->_mbstate, 0, sizeof (_mbstate_t)); |
/* fp->_cookie = <any>; */ /* caller sets cookie, _read/_write etc */ |
fp->_ub._base = NULL; /* no ungetc buffer */ |
fp->_ub._size = 0; |
fp->_lb._base = NULL; /* no line buffer */ |
fp->_lb._size = 0; |
|
return fp; |
} |
|
/* |
* exit() calls _cleanup() through *__cleanup, set whenever we |
* open or buffer a file. This chicanery is done so that programs |
* that do not use stdio need not link it all in. |
* |
* The name `_cleanup' is, alas, fairly well known outside stdio. |
*/ |
|
_VOID |
_DEFUN(_cleanup_r, (ptr), |
struct _reent *ptr) |
{ |
_CAST_VOID _fwalk(ptr, fclose); |
/* _CAST_VOID _fwalk (ptr, fflush); */ /* `cheating' */ |
} |
|
#ifndef _REENT_ONLY |
_VOID |
_DEFUN_VOID(_cleanup) |
{ |
_cleanup_r (_GLOBAL_REENT); |
} |
#endif |
|
/* |
* __sinit() is called whenever stdio's internal variables must be set up. |
*/ |
|
_VOID |
_DEFUN(__sinit, (s), |
struct _reent *s) |
{ |
__sinit_lock_acquire (); |
|
if (s->__sdidinit) |
{ |
__sinit_lock_release (); |
return; |
} |
|
/* make sure we clean up on exit */ |
s->__cleanup = _cleanup_r; /* conservative */ |
s->__sdidinit = 1; |
|
s->__sglue._next = NULL; |
#ifndef _REENT_SMALL |
s->__sglue._niobs = 3; |
s->__sglue._iobs = &s->__sf[0]; |
#else |
s->__sglue._niobs = 0; |
s->__sglue._iobs = NULL; |
s->_stdin = __sfp(s); |
s->_stdout = __sfp(s); |
s->_stderr = __sfp(s); |
#endif |
|
std (s->_stdin, __SRD, 0, s); |
|
/* On platforms that have true file system I/O, we can verify |
whether stdout is an interactive terminal or not, as part of |
__smakebuf on first use of the stream. For all other platforms, |
we will default to line buffered mode here. Technically, POSIX |
requires both stdin and stdout to be line-buffered, but tradition |
leaves stdin alone on systems without fcntl. */ |
#ifdef HAVE_FCNTL |
std (s->_stdout, __SWR, 1, s); |
#else |
std (s->_stdout, __SWR | __SLBF, 1, s); |
#endif |
|
/* POSIX requires stderr to be opened for reading and writing, even |
when the underlying fd 2 is write-only. */ |
std (s->_stderr, __SRW | __SNBF, 2, s); |
|
__sinit_lock_release (); |
} |
|
#ifndef __SINGLE_THREAD__ |
|
__LOCK_INIT_RECURSIVE(static, __sfp_lock); |
__LOCK_INIT_RECURSIVE(static, __sinit_lock); |
|
_VOID |
_DEFUN_VOID(__sfp_lock_acquire) |
{ |
__lock_acquire_recursive (__sfp_lock); |
} |
|
_VOID |
_DEFUN_VOID(__sfp_lock_release) |
{ |
__lock_release_recursive (__sfp_lock); |
} |
|
_VOID |
_DEFUN_VOID(__sinit_lock_acquire) |
{ |
__lock_acquire_recursive (__sinit_lock); |
} |
|
_VOID |
_DEFUN_VOID(__sinit_lock_release) |
{ |
__lock_release_recursive (__sinit_lock); |
} |
|
/* Walkable file locking routine. */ |
static int |
_DEFUN(__fp_lock, (ptr), |
FILE * ptr) |
{ |
_flockfile (ptr); |
|
return 0; |
} |
|
/* Walkable file unlocking routine. */ |
static int |
_DEFUN(__fp_unlock, (ptr), |
FILE * ptr) |
{ |
_funlockfile (ptr); |
|
return 0; |
} |
|
_VOID |
_DEFUN_VOID(__fp_lock_all) |
{ |
__sfp_lock_acquire (); |
|
_CAST_VOID _fwalk (_REENT, __fp_lock); |
} |
|
_VOID |
_DEFUN_VOID(__fp_unlock_all) |
{ |
_CAST_VOID _fwalk (_REENT, __fp_unlock); |
|
__sfp_lock_release (); |
} |
#endif |