xref: /minix3/lib/libc/stdio/findfp.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1f14fb602SLionel Sambuc /*	$NetBSD: findfp.c,v 1.28 2012/03/27 15:05:42 christos Exp $	*/
22fe8fb19SBen Gras 
32fe8fb19SBen Gras /*-
42fe8fb19SBen Gras  * Copyright (c) 1990, 1993
52fe8fb19SBen Gras  *	The Regents of the University of California.  All rights reserved.
62fe8fb19SBen Gras  *
72fe8fb19SBen Gras  * This code is derived from software contributed to Berkeley by
82fe8fb19SBen Gras  * Chris Torek.
92fe8fb19SBen Gras  *
102fe8fb19SBen Gras  * Redistribution and use in source and binary forms, with or without
112fe8fb19SBen Gras  * modification, are permitted provided that the following conditions
122fe8fb19SBen Gras  * are met:
132fe8fb19SBen Gras  * 1. Redistributions of source code must retain the above copyright
142fe8fb19SBen Gras  *    notice, this list of conditions and the following disclaimer.
152fe8fb19SBen Gras  * 2. Redistributions in binary form must reproduce the above copyright
162fe8fb19SBen Gras  *    notice, this list of conditions and the following disclaimer in the
172fe8fb19SBen Gras  *    documentation and/or other materials provided with the distribution.
182fe8fb19SBen Gras  * 3. Neither the name of the University nor the names of its contributors
192fe8fb19SBen Gras  *    may be used to endorse or promote products derived from this software
202fe8fb19SBen Gras  *    without specific prior written permission.
212fe8fb19SBen Gras  *
222fe8fb19SBen Gras  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
232fe8fb19SBen Gras  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
242fe8fb19SBen Gras  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
252fe8fb19SBen Gras  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
262fe8fb19SBen Gras  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
272fe8fb19SBen Gras  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
282fe8fb19SBen Gras  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
292fe8fb19SBen Gras  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
302fe8fb19SBen Gras  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
312fe8fb19SBen Gras  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
322fe8fb19SBen Gras  * SUCH DAMAGE.
332fe8fb19SBen Gras  */
342fe8fb19SBen Gras 
352fe8fb19SBen Gras #include <sys/cdefs.h>
362fe8fb19SBen Gras #if defined(LIBC_SCCS) && !defined(lint)
372fe8fb19SBen Gras #if 0
382fe8fb19SBen Gras static char sccsid[] = "@(#)findfp.c	8.2 (Berkeley) 1/4/94";
392fe8fb19SBen Gras #else
40f14fb602SLionel Sambuc __RCSID("$NetBSD: findfp.c,v 1.28 2012/03/27 15:05:42 christos Exp $");
412fe8fb19SBen Gras #endif
422fe8fb19SBen Gras #endif /* LIBC_SCCS and not lint */
432fe8fb19SBen Gras 
442fe8fb19SBen Gras #include "namespace.h"
452fe8fb19SBen Gras #include <sys/param.h>
462fe8fb19SBen Gras #include <unistd.h>
472fe8fb19SBen Gras #include <stdio.h>
482fe8fb19SBen Gras #include <errno.h>
492fe8fb19SBen Gras #include <stdlib.h>
502fe8fb19SBen Gras #include <string.h>
512fe8fb19SBen Gras #include "reentrant.h"
522fe8fb19SBen Gras #include "local.h"
532fe8fb19SBen Gras #include "glue.h"
542fe8fb19SBen Gras 
552fe8fb19SBen Gras int	__sdidinit;
562fe8fb19SBen Gras 
572fe8fb19SBen Gras #define	NDYNAMIC 10		/* add ten more whenever necessary */
582fe8fb19SBen Gras 
5984d9c625SLionel Sambuc #if !defined(_LIBMINC) && !defined(__kernel__) && defined(__minix)
602fe8fb19SBen Gras 
61f14fb602SLionel Sambuc #define	std(flags, file) { \
62f14fb602SLionel Sambuc 	._p = NULL, \
63f14fb602SLionel Sambuc 	._r = 0, \
64f14fb602SLionel Sambuc 	._w = 0, \
65f14fb602SLionel Sambuc 	._flags = (flags), \
66f14fb602SLionel Sambuc 	._file = (file),  \
67f14fb602SLionel Sambuc 	._bf = { ._base = NULL, ._size = 0 }, \
68f14fb602SLionel Sambuc 	._lbfsize = 0,  \
69f14fb602SLionel Sambuc 	._cookie = __sF + (file), \
70f14fb602SLionel Sambuc 	._close = __sclose, \
71f14fb602SLionel Sambuc 	._read = __sread, \
72f14fb602SLionel Sambuc 	._seek = __sseek, \
73f14fb602SLionel Sambuc 	._write = __swrite, \
74f14fb602SLionel Sambuc 	._ext = { ._base = (void *)(__sFext + (file)), ._size = 0 }, \
75f14fb602SLionel Sambuc 	._up = NULL, \
76f14fb602SLionel Sambuc         ._ur = 0, \
77f14fb602SLionel Sambuc 	._ubuf = { [0] = '\0', [1] = '\0', [2] = '\0' }, \
78f14fb602SLionel Sambuc 	._nbuf = { [0] = '\0' }, \
79f14fb602SLionel Sambuc 	._flush = NULL, \
80f14fb602SLionel Sambuc 	._lb_unused = { '\0' }, \
81f14fb602SLionel Sambuc 	._blksize = 0, \
82f14fb602SLionel Sambuc 	._offset = (off_t)0, \
83f14fb602SLionel Sambuc }
84f14fb602SLionel Sambuc 
85f14fb602SLionel Sambuc #else
86f14fb602SLionel Sambuc 
87f14fb602SLionel Sambuc #define	std(flags, file) { \
88f14fb602SLionel Sambuc 	._p = NULL, \
89f14fb602SLionel Sambuc 	._r = 0, \
90f14fb602SLionel Sambuc 	._w = 0, \
91f14fb602SLionel Sambuc 	._flags = (flags), \
92f14fb602SLionel Sambuc 	._file = (file),  \
93f14fb602SLionel Sambuc 	._bf = { ._base = NULL, ._size = 0 }, \
94f14fb602SLionel Sambuc 	._lbfsize = 0,  \
95f14fb602SLionel Sambuc 	._cookie = __sF + (file), \
96f14fb602SLionel Sambuc 	._close = NULL, \
97f14fb602SLionel Sambuc 	._read = NULL, \
98f14fb602SLionel Sambuc 	._seek = NULL, \
99f14fb602SLionel Sambuc 	._write = NULL, \
100f14fb602SLionel Sambuc 	._ext = { ._base = (void *)(__sFext + (file)), ._size = 0 }, \
101f14fb602SLionel Sambuc 	._up = NULL, \
102f14fb602SLionel Sambuc         ._ur = 0, \
103f14fb602SLionel Sambuc 	._ubuf = { [0] = '\0', [1] = '\0', [2] = '\0' }, \
104f14fb602SLionel Sambuc 	._nbuf = { [0] = '\0' }, \
105f14fb602SLionel Sambuc 	._flush = NULL, \
106f14fb602SLionel Sambuc 	._lb_unused = { '\0' }, \
107f14fb602SLionel Sambuc 	._blksize = 0, \
108f14fb602SLionel Sambuc 	._offset = (off_t)0, \
109f14fb602SLionel Sambuc }
110f14fb602SLionel Sambuc 
111f14fb602SLionel Sambuc #endif /* !defined(_LIBMINC) && !defined(__kernel__) */
112f14fb602SLionel Sambuc 
113*0a6a1f1dSLionel Sambuc #if !defined(__kernel__) && defined(__minix)
1142fe8fb19SBen Gras 				/* the usual - (stdin + stdout + stderr) */
1152fe8fb19SBen Gras static FILE usual[FOPEN_MAX - 3];
1162fe8fb19SBen Gras static struct __sfileext usualext[FOPEN_MAX - 3];
1172fe8fb19SBen Gras static struct glue uglue = { 0, FOPEN_MAX - 3, usual };
118*0a6a1f1dSLionel Sambuc #endif /* !defined(__kernel__) && defined(__minix) */
1192fe8fb19SBen Gras 
1202fe8fb19SBen Gras #if defined(_REENTRANT) && !defined(__lint__) /* XXX lint is busted */
1212fe8fb19SBen Gras #define	STDEXT { ._lock = MUTEX_INITIALIZER, ._lockcond = COND_INITIALIZER }
1222fe8fb19SBen Gras struct __sfileext __sFext[3] = { STDEXT,
1232fe8fb19SBen Gras 				 STDEXT,
1242fe8fb19SBen Gras 				 STDEXT};
1252fe8fb19SBen Gras #else
1262fe8fb19SBen Gras struct __sfileext __sFext[3];
1272fe8fb19SBen Gras #endif
1282fe8fb19SBen Gras 
1292fe8fb19SBen Gras FILE __sF[3] = {
1302fe8fb19SBen Gras 	std(__SRD, STDIN_FILENO),		/* stdin */
1312fe8fb19SBen Gras 	std(__SWR, STDOUT_FILENO),		/* stdout */
1322fe8fb19SBen Gras 	std(__SWR|__SNBF, STDERR_FILENO)	/* stderr */
1332fe8fb19SBen Gras };
134f14fb602SLionel Sambuc 
13584d9c625SLionel Sambuc #if !defined(__kernel__) && defined(__minix)
1362fe8fb19SBen Gras struct glue __sglue = { &uglue, 3, __sF };
1372fe8fb19SBen Gras 
138f14fb602SLionel Sambuc void f_prealloc(void);
1392fe8fb19SBen Gras 
1402fe8fb19SBen Gras #ifdef _REENTRANT
1412fe8fb19SBen Gras rwlock_t __sfp_lock = RWLOCK_INITIALIZER;
1422fe8fb19SBen Gras #endif
1432fe8fb19SBen Gras 
1442fe8fb19SBen Gras static struct glue *
moreglue(int n)145f14fb602SLionel Sambuc moreglue(int n)
1462fe8fb19SBen Gras {
1472fe8fb19SBen Gras 	struct glue *g;
1482fe8fb19SBen Gras 	FILE *p;
1492fe8fb19SBen Gras 	struct __sfileext *pext;
1502fe8fb19SBen Gras 	static FILE empty;
1512fe8fb19SBen Gras 
152f14fb602SLionel Sambuc 	g = malloc(sizeof(*g) + ALIGNBYTES + n * sizeof(FILE)
1532fe8fb19SBen Gras 	    + n * sizeof(struct __sfileext));
1542fe8fb19SBen Gras 	if (g == NULL)
155f14fb602SLionel Sambuc 		return NULL;
1562fe8fb19SBen Gras 	p = (FILE *)ALIGN((u_long)(g + 1));
1572fe8fb19SBen Gras 	g->next = NULL;
1582fe8fb19SBen Gras 	g->niobs = n;
1592fe8fb19SBen Gras 	g->iobs = p;
1602fe8fb19SBen Gras 	pext = (void *)(p + n);
1612fe8fb19SBen Gras 	while (--n >= 0) {
1622fe8fb19SBen Gras 		*p = empty;
1632fe8fb19SBen Gras 		_FILEEXT_SETUP(p, pext);
1642fe8fb19SBen Gras 		p++;
1652fe8fb19SBen Gras 		pext++;
1662fe8fb19SBen Gras 	}
167f14fb602SLionel Sambuc 	return g;
1682fe8fb19SBen Gras }
1692fe8fb19SBen Gras 
1702fe8fb19SBen Gras void
__sfpinit(FILE * fp)1712fe8fb19SBen Gras __sfpinit(FILE *fp)
1722fe8fb19SBen Gras {
1732fe8fb19SBen Gras 	fp->_flags = 1;		/* reserve this slot; caller sets real flags */
1742fe8fb19SBen Gras 	fp->_p = NULL;		/* no current pointer */
1752fe8fb19SBen Gras 	fp->_w = 0;		/* nothing to read or write */
1762fe8fb19SBen Gras 	fp->_r = 0;
1772fe8fb19SBen Gras 	fp->_bf._base = NULL;	/* no buffer */
1782fe8fb19SBen Gras 	fp->_bf._size = 0;
1792fe8fb19SBen Gras 	fp->_lbfsize = 0;	/* not line buffered */
1802fe8fb19SBen Gras 	fp->_file = -1;		/* no file */
1812fe8fb19SBen Gras /*	fp->_cookie = <any>; */	/* caller sets cookie, _read/_write etc */
182f14fb602SLionel Sambuc 	fp->_flush = NULL;	/* default flush */
1832fe8fb19SBen Gras 	_UB(fp)._base = NULL;	/* no ungetc buffer */
1842fe8fb19SBen Gras 	_UB(fp)._size = 0;
1852fe8fb19SBen Gras 	memset(WCIO_GET(fp), 0, sizeof(struct wchar_io_data));
1862fe8fb19SBen Gras }
1872fe8fb19SBen Gras 
1882fe8fb19SBen Gras /*
1892fe8fb19SBen Gras  * Find a free FILE for fopen et al.
1902fe8fb19SBen Gras  */
1912fe8fb19SBen Gras FILE *
__sfp(void)192f14fb602SLionel Sambuc __sfp(void)
1932fe8fb19SBen Gras {
1942fe8fb19SBen Gras 	FILE *fp;
1952fe8fb19SBen Gras 	int n;
1962fe8fb19SBen Gras 	struct glue *g;
1972fe8fb19SBen Gras 
1982fe8fb19SBen Gras 	if (!__sdidinit)
1992fe8fb19SBen Gras 		__sinit();
2002fe8fb19SBen Gras 
2012fe8fb19SBen Gras 	rwlock_wrlock(&__sfp_lock);
2022fe8fb19SBen Gras 	for (g = &__sglue;; g = g->next) {
2032fe8fb19SBen Gras 		for (fp = g->iobs, n = g->niobs; --n >= 0; fp++)
2042fe8fb19SBen Gras 			if (fp->_flags == 0)
2052fe8fb19SBen Gras 				goto found;
2062fe8fb19SBen Gras 		if (g->next == NULL && (g->next = moreglue(NDYNAMIC)) == NULL)
2072fe8fb19SBen Gras 			break;
2082fe8fb19SBen Gras 	}
2092fe8fb19SBen Gras 	rwlock_unlock(&__sfp_lock);
210f14fb602SLionel Sambuc 	return NULL;
2112fe8fb19SBen Gras found:
2122fe8fb19SBen Gras 	__sfpinit(fp);
2132fe8fb19SBen Gras 	rwlock_unlock(&__sfp_lock);
214f14fb602SLionel Sambuc 	return fp;
2152fe8fb19SBen Gras }
2162fe8fb19SBen Gras 
2172fe8fb19SBen Gras /*
2182fe8fb19SBen Gras  * XXX.  Force immediate allocation of internal memory.  Not used by stdio,
2192fe8fb19SBen Gras  * but documented historically for certain applications.  Bad applications.
2202fe8fb19SBen Gras  */
2212fe8fb19SBen Gras void
f_prealloc(void)222f14fb602SLionel Sambuc f_prealloc(void)
2232fe8fb19SBen Gras {
22484d9c625SLionel Sambuc #if !defined(_LIBMINC) && defined(__minix)
2252fe8fb19SBen Gras 	struct glue *g;
2262fe8fb19SBen Gras 	int n;
2272fe8fb19SBen Gras 
2282fe8fb19SBen Gras 	n = (int)sysconf(_SC_OPEN_MAX) - FOPEN_MAX + 20; /* 20 for slop. */
2292fe8fb19SBen Gras 	for (g = &__sglue; (n -= g->niobs) > 0 && g->next; g = g->next)
230f14fb602SLionel Sambuc 		continue;
2312fe8fb19SBen Gras 	if (n > 0)
2322fe8fb19SBen Gras 		g->next = moreglue(n);
233*0a6a1f1dSLionel Sambuc #endif /* !defined(_LIBMINC) && defined(__minix) */
2342fe8fb19SBen Gras }
2352fe8fb19SBen Gras 
2362fe8fb19SBen Gras /*
2372fe8fb19SBen Gras  * exit() calls _cleanup() through *__cleanup, set whenever we
2382fe8fb19SBen Gras  * open or buffer a file.  This chicanery is done so that programs
2392fe8fb19SBen Gras  * that do not use stdio need not link it all in.
2402fe8fb19SBen Gras  *
2412fe8fb19SBen Gras  * The name `_cleanup' is, alas, fairly well known outside stdio.
2422fe8fb19SBen Gras  */
2432fe8fb19SBen Gras void
_cleanup(void)244f14fb602SLionel Sambuc _cleanup(void)
2452fe8fb19SBen Gras {
24684d9c625SLionel Sambuc #if !defined(_LIBMINC) && defined(__minix)
2472fe8fb19SBen Gras 	/* (void) _fwalk(fclose); */
2482fe8fb19SBen Gras 	(void) fflush(NULL);			/* `cheating' */
249*0a6a1f1dSLionel Sambuc #endif /* !defined(_LIBMINC) && defined(__minix) */
2502fe8fb19SBen Gras }
2512fe8fb19SBen Gras 
2522fe8fb19SBen Gras /*
2532fe8fb19SBen Gras  * __sinit() is called whenever stdio's internal variables must be set up.
2542fe8fb19SBen Gras  */
2552fe8fb19SBen Gras void
__sinit(void)256f14fb602SLionel Sambuc __sinit(void)
2572fe8fb19SBen Gras {
2582fe8fb19SBen Gras 	int i;
2592fe8fb19SBen Gras 
2602fe8fb19SBen Gras 	for (i = 0; i < FOPEN_MAX - 3; i++)
2612fe8fb19SBen Gras 		_FILEEXT_SETUP(&usual[i], &usualext[i]);
2622fe8fb19SBen Gras 
2632fe8fb19SBen Gras 	/* make sure we clean up on exit */
2642fe8fb19SBen Gras 	__cleanup = _cleanup;		/* conservative */
2652fe8fb19SBen Gras 	__sdidinit = 1;
2662fe8fb19SBen Gras }
267*0a6a1f1dSLionel Sambuc #endif /* !defined(__kernel__) && defined(__minix) */
268