1/*-
2 * Copyright (c) 1990, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Chris Torek.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 *	This product includes software developed by the University of
19 *	California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 *    may be used to endorse or promote products derived from this software
22 *    without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37//#include <sys/param.h>
38#include <unistd.h>
39#include <stdio.h>
40#include <errno.h>
41#include <stdlib.h>
42#include <string.h>
43
44#include <errno_private.h>
45
46#include "local.h"
47#include "glue.h"
48
49/* Prototype needed */
50void f_prealloc(void);
51
52int	__sdidinit;
53
54/* XXX - these belong in sys/param.h
55 * Round p (pointer or byte index) up to a correctly-aligned value
56 * for all data types (int, long, ...).   The result is u_int and
57 * must be cast to any desired pointer type.
58 */
59#define ALIGNBYTES      (sizeof(int) - 1)
60#define ALIGN(p)        (((u_int)(p) + ALIGNBYTES) &~ ALIGNBYTES)
61
62#define	NDYNAMIC 10		/* add ten more whenever necessary */
63
64#define	std(flags, file) \
65	{0,0,0,flags,file,{0},0,__sF+file,__sclose,__sread,__sseek,__swrite}
66/*	 p r w flags file _bf z  cookie      close    read    seek    write */
67
68				/* the usual - (stdin + stdout + stderr) */
69static FILE usual[FOPEN_MAX - 3];
70static struct glue uglue = { 0, FOPEN_MAX - 3, usual };
71
72FILE __sF[3] = {
73	std(__SRD, STDIN_FILENO),		    /* stdin */
74	std(__SWR, STDOUT_FILENO),		    /* stdout */
75	std(__SWR|__SNBF, STDERR_FILENO)	/* stderr */
76};
77
78struct glue __sglue = { &uglue, 3, __sF };
79
80static struct glue *
81moreglue(n)
82	register int n;
83{
84	register struct glue *g;
85	register FILE *p;
86	static FILE empty;
87
88	g = (struct glue *)malloc(sizeof(*g) + ALIGNBYTES + n * sizeof(FILE));
89	if (g == NULL)
90		return (NULL);
91	p = (FILE *)ALIGN(g + 1);
92	g->next = NULL;
93	g->niobs = n;
94	g->iobs = p;
95	while (--n >= 0)
96		*p++ = empty;
97	return (g);
98}
99
100/*
101 * Find a free FILE for fopen et al.
102 */
103FILE *
104__sfp()
105{
106	register FILE *fp;
107	register int n;
108	register struct glue *g;
109
110	if (!__sdidinit)
111		__sinit();
112	for (g = &__sglue;; g = g->next) {
113		for (fp = g->iobs, n = g->niobs; --n >= 0; fp++)
114			if (fp->_flags == 0)
115				goto found;
116		if (g->next == NULL && (g->next = moreglue(NDYNAMIC)) == NULL)
117			break;
118	}
119	return (NULL);
120found:
121	fp->_flags = 1;		/* reserve this slot; caller sets real flags */
122	fp->_p = NULL;		/* no current pointer */
123	fp->_w = 0;		/* nothing to read or write */
124	fp->_r = 0;
125	fp->_bf._base = NULL;	/* no buffer */
126	fp->_bf._size = 0;
127	fp->_lbfsize = 0;	/* not line buffered */
128	fp->_file = -1;		/* no file */
129/*	fp->_cookie = <any>; */	/* caller sets cookie, _read/_write etc */
130	fp->_ub._base = NULL;	/* no ungetc buffer */
131	fp->_ub._size = 0;
132	fp->_lb._base = NULL;	/* no line buffer */
133	fp->_lb._size = 0;
134	return (fp);
135}
136
137/*
138 * XXX.  Force immediate allocation of internal memory.  Not used by stdio,
139 * but documented historically for certain applications.  Bad applications.
140 */
141void
142f_prealloc()
143{
144	register struct glue *g;
145	int n;
146
147	n = getdtablesize() - FOPEN_MAX + 20;		/* 20 for slop. */
148	for (g = &__sglue; (n -= g->niobs) > 0 && g->next; g = g->next)
149		/* void */;
150	if (n > 0)
151		g->next = moreglue(n);
152}
153
154/*
155 * exit() calls _cleanup() through *__cleanup, set whenever we
156 * open or buffer a file.  This chicanery is done so that programs
157 * that do not use stdio need not link it all in.
158 *
159 * The name `_cleanup' is, alas, fairly well known outside stdio.
160 */
161void
162_cleanup()
163{
164	/* (void) _fwalk(fclose); */
165	(void) _fwalk(__sflush);		/* `cheating' */
166}
167
168/*
169 * __sinit() is called whenever stdio's internal variables must be set up.
170 */
171void
172__sinit()
173{
174	/* make sure we clean up on exit */
175	_IO_cleanup = _cleanup;		/* conservative */
176	__sdidinit = 1;
177}
178