1 /*- 2 * Copyright (c) 1990 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Chris Torek. 7 * 8 * %sccs.include.redist.c% 9 */ 10 11 #if defined(LIBC_SCCS) && !defined(lint) 12 static char sccsid[] = "@(#)findfp.c 5.10 (Berkeley) 02/24/91"; 13 #endif /* LIBC_SCCS and not lint */ 14 15 #include <unistd.h> 16 #include <stdio.h> 17 #include <errno.h> 18 #include <stdlib.h> 19 #include <string.h> 20 #include "local.h" 21 #include "glue.h" 22 23 int __sdidinit; 24 25 #define NSTATIC 20 /* stdin + stdout + stderr + the usual */ 26 #define NDYNAMIC 10 /* add ten more whenever necessary */ 27 28 #define std(flags, file) \ 29 {0,0,0,flags,file,{0},0,__sF+file,__sclose,__sread,__sseek,__swrite} 30 /* p r w flags file _bf z cookie close read seek write */ 31 32 static FILE usual[NSTATIC - 3]; /* the usual */ 33 static struct glue uglue = { 0, NSTATIC - 3, usual }; 34 35 FILE __sF[3] = { 36 std(__SRD, STDIN_FILENO), /* stdin */ 37 std(__SWR, STDOUT_FILENO), /* stdout */ 38 std(__SWR|__SNBF, STDERR_FILENO) /* stderr */ 39 }; 40 struct glue __sglue = { &uglue, 3, __sF }; 41 42 static struct glue * 43 moreglue(n) 44 register int n; 45 { 46 register struct glue *g; 47 register FILE *p; 48 static FILE empty; 49 50 g = (struct glue *)malloc(sizeof(*g) + n * sizeof(FILE)); 51 if (g == NULL) 52 return (NULL); 53 p = (FILE *)(g + 1); 54 g->next = NULL; 55 g->niobs = n; 56 g->iobs = p; 57 while (--n >= 0) 58 *p++ = empty; 59 return (g); 60 } 61 62 /* 63 * Find a free FILE for fopen et al. 64 */ 65 FILE * 66 __sfp() 67 { 68 register FILE *fp; 69 register int n; 70 register struct glue *g; 71 72 if (!__sdidinit) 73 __sinit(); 74 for (g = &__sglue;; g = g->next) { 75 for (fp = g->iobs, n = g->niobs; --n >= 0; fp++) 76 if (fp->_flags == 0) 77 goto found; 78 if (g->next == NULL && (g->next = moreglue(NDYNAMIC)) == NULL) 79 break; 80 } 81 return (NULL); 82 found: 83 fp->_flags = 1; /* reserve this slot; caller sets real flags */ 84 fp->_p = NULL; /* no current pointer */ 85 fp->_w = 0; /* nothing to read or write */ 86 fp->_r = 0; 87 fp->_bf._base = NULL; /* no buffer */ 88 fp->_bf._size = 0; 89 fp->_lbfsize = 0; /* not line buffered */ 90 fp->_file = -1; /* no file */ 91 /* fp->_cookie = <any>; */ /* caller sets cookie, _read/_write etc */ 92 fp->_ub._base = NULL; /* no ungetc buffer */ 93 fp->_ub._size = 0; 94 fp->_lb._base = NULL; /* no line buffer */ 95 fp->_lb._size = 0; 96 return (fp); 97 } 98 99 /* 100 * XXX. Force immediate allocation of internal memory. Not used by stdio, 101 * but documented historically for certain applications. Bad applications. 102 */ 103 f_prealloc() 104 { 105 int n = getdtablesize() - NSTATIC + 20; /* 20 for slop */ 106 register struct glue *g; 107 108 for (g = &__sglue; (n -= g->niobs) > 0 && g->next; g = g->next) 109 /* void */; 110 if (n > 0) 111 g->next = moreglue(n); 112 } 113 114 /* 115 * exit() calls _cleanup() through *__cleanup, set whenever we 116 * open or buffer a file. This chicanery is done so that programs 117 * that do not use stdio need not link it all in. 118 * 119 * The name `_cleanup' is, alas, fairly well known outside stdio. 120 */ 121 void 122 _cleanup() 123 { 124 /* (void) _fwalk(fclose); */ 125 (void) _fwalk(__sflush); /* `cheating' */ 126 } 127 128 /* 129 * __sinit() is called whenever stdio's internal variables must be set up. 130 */ 131 void 132 __sinit() 133 { 134 /* make sure we clean up on exit */ 135 __cleanup = _cleanup; /* conservative */ 136 __sdidinit = 1; 137 } 138