| /** @file | |
| Copyright (c) 2011, Intel Corporation. All rights reserved.<BR> | |
| This program and the accompanying materials are licensed and made available under | |
| the terms and conditions of the BSD License that accompanies this distribution. | |
| The full text of the license may be found at | |
| http://opensource.org/licenses/bsd-license. | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| * Copyright (c) 1990, 1993 | |
| * The Regents of the University of California. All rights reserved. | |
| * | |
| * This code is derived from software contributed to Berkeley by | |
| * Chris Torek. | |
| * | |
| * Redistribution and use in source and binary forms, with or without | |
| * modification, are permitted provided that the following conditions | |
| * are met: | |
| * 1. Redistributions of source code must retain the above copyright | |
| * notice, this list of conditions and the following disclaimer. | |
| * 2. Redistributions in binary form must reproduce the above copyright | |
| * notice, this list of conditions and the following disclaimer in the | |
| * documentation and/or other materials provided with the distribution. | |
| * 3. Neither the name of the University nor the names of its contributors | |
| * may be used to endorse or promote products derived from this software | |
| * without specific prior written permission. | |
| * | |
| * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
| * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
| * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
| * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
| * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
| * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
| * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
| * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
| * SUCH DAMAGE. | |
| NetBSD: findfp.c,v 1.23 2006/10/07 21:40:46 thorpej Exp | |
| findfp.c 8.2 (Berkeley) 1/4/94 | |
| **/ | |
| #include <LibConfig.h> | |
| #include <sys/EfiCdefs.h> | |
| #include "namespace.h" | |
| #include <sys/param.h> | |
| #include <stdio.h> | |
| #include <errno.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <unistd.h> | |
| #include "reentrant.h" | |
| #include "local.h" | |
| #include "glue.h" | |
| #include <MainData.h> | |
| int __sdidinit; | |
| #define NDYNAMIC 10 /* add ten more whenever necessary */ | |
| #define std(flags, file) \ | |
| /* p r w flags file bf lfbsize cookie close */ \ | |
| { NULL, 0, 0, flags, file, { NULL, 0 }, 0, __sF + file, __sclose, \ | |
| /* read seek write ext up */ \ | |
| __sread, __sseek, __swrite, { (void *)(__sFext + file), 0 }, NULL, \ | |
| /* ur ubuf, nbuf lb blksize offset */ \ | |
| 0, { '\0', '\0', '\0' }, { '\0' }, { NULL, 0 }, 0, (fpos_t)0 } | |
| /* the usual - (stdin + stdout + stderr) */ | |
| static FILE usual[FOPEN_MAX - 3]; | |
| static struct __sfileext usualext[FOPEN_MAX - 3]; | |
| static struct glue uglue = { 0, FOPEN_MAX - 3, usual }; | |
| #if defined(_REENTRANT) && !defined(__lint__) /* XXX lint is busted */ | |
| #define STDEXT { ._lock = MUTEX_INITIALIZER, ._lockcond = COND_INITIALIZER } | |
| struct __sfileext __sFext[3] = { STDEXT, | |
| STDEXT, | |
| STDEXT}; | |
| #else | |
| struct __sfileext __sFext[3]; | |
| #endif | |
| FILE __sF[3] = { | |
| std(__SRD, STDIN_FILENO), /* stdin */ | |
| std(__SWR, STDOUT_FILENO), /* stdout */ | |
| std(__SWR|__SNBF, STDERR_FILENO) /* stderr */ | |
| }; | |
| struct glue __sglue = { &uglue, 3, __sF }; | |
| static struct glue *moreglue(int); | |
| void f_prealloc(void); | |
| #ifdef _REENTRANT | |
| rwlock_t __sfp_lock = RWLOCK_INITIALIZER; | |
| #endif | |
| static struct glue * | |
| moreglue(int n) | |
| { | |
| struct glue *g; | |
| FILE *p; | |
| struct __sfileext *pext; | |
| static FILE empty; | |
| g = (struct glue *)malloc(sizeof(*g) + ALIGNBYTES + n * sizeof(FILE) | |
| + n * sizeof(struct __sfileext)); | |
| if (g == NULL) | |
| return (NULL); | |
| p = (FILE *)ALIGN((g + 1)); | |
| g->next = NULL; | |
| g->niobs = n; | |
| g->iobs = p; | |
| pext = (void *)(p + n); | |
| while (--n >= 0) { | |
| *p = empty; | |
| _FILEEXT_SETUP(p, pext); | |
| p++; | |
| pext++; | |
| } | |
| return (g); | |
| } | |
| /* | |
| * Find a free FILE for fopen et al. | |
| */ | |
| FILE * | |
| __sfp() | |
| { | |
| FILE *fp; | |
| int n; | |
| struct glue *g; | |
| if (!__sdidinit) | |
| __sinit(); | |
| rwlock_wrlock(&__sfp_lock); | |
| for (g = &__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 = moreglue(NDYNAMIC)) == NULL) | |
| break; | |
| } | |
| rwlock_unlock(&__sfp_lock); | |
| return (NULL); | |
| found: | |
| fp->_flags = 1; /* reserve this slot; caller sets real flags */ | |
| 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 */ | |
| fp->_file = -1; /* no file */ | |
| /* fp->_cookie = <any>; */ /* caller sets cookie, _read/_write etc */ | |
| _UB(fp)._base = NULL; /* no ungetc buffer */ | |
| _UB(fp)._size = 0; | |
| fp->_lb._base = NULL; /* no line buffer */ | |
| fp->_lb._size = 0; | |
| memset(WCIO_GET(fp), 0, sizeof(struct wchar_io_data)); | |
| rwlock_unlock(&__sfp_lock); | |
| return (fp); | |
| } | |
| #if 0 | |
| /* | |
| * XXX. Force immediate allocation of internal memory. Not used by stdio, | |
| * but documented historically for certain applications. Bad applications. | |
| */ | |
| void | |
| f_prealloc() | |
| { | |
| struct glue *g; | |
| int n; | |
| n = (int)sysconf(_SC_OPEN_MAX) - FOPEN_MAX + 20; /* 20 for slop. */ | |
| for (g = &__sglue; (n -= g->niobs) > 0 && g->next; g = g->next) | |
| /* void */; | |
| if (n > 0) | |
| g->next = moreglue(n); | |
| } | |
| #endif | |
| /* | |
| * exit() calls _cleanup() through *gMD->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 | |
| _cleanup( void ) | |
| { | |
| /* (void) _fwalk(fclose); */ | |
| (void) fflush(NULL); /* `cheating' */ | |
| } | |
| /* | |
| * __sinit() is called whenever stdio's internal variables must be set up. | |
| */ | |
| void | |
| __sinit( void ) | |
| { | |
| int i; | |
| for (i = 0; i < FOPEN_MAX - 3; i++) | |
| _FILEEXT_SETUP(&usual[i], &usualext[i]); | |
| /* make sure we clean up on exit */ | |
| gMD->cleanup = _cleanup; /* conservative */ | |
| __sdidinit = 1; | |
| } |