sl@0: /* FINDFP.C
sl@0:  * 
sl@0:  * Portions Copyright (c) 1990-2008 Nokia Corporation and/or its subsidiary(-ies).
sl@0:  * All rights reserved.
sl@0:  */
sl@0: 
sl@0: /* No user fns here.  Pesch 15apr92. */
sl@0: 
sl@0: /*
sl@0:  * Copyright (c) 1990 The Regents of the University of California.
sl@0:  * All rights reserved.
sl@0:  *
sl@0:  * Redistribution and use in source and binary forms are permitted
sl@0:  * provided that the above copyright notice and this paragraph are
sl@0:  * duplicated in all such forms and that any documentation,
sl@0:  * advertising materials, and other materials related to such
sl@0:  * distribution and use acknowledge that the software was developed
sl@0:  * by the University of California, Berkeley.  The name of the
sl@0:  * University may not be used to endorse or promote products derived
sl@0:  * from this software without specific prior written permission.
sl@0:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
sl@0:  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
sl@0:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
sl@0:  */
sl@0: 
sl@0: #include <stdio_r.h>
sl@0: #include <stdlib_r.h>
sl@0: #include <errno.h>
sl@0: #include <string.h>
sl@0: #include "LOCAL.H"
sl@0: 
sl@0: /* Initialise a FILE structure to a starting state */
sl@0: #ifdef __GCCXML__
sl@0: static void
sl@0: _std (FILE *ptr, int flags, int file, struct _reent *data)
sl@0: #else
sl@0: static void
sl@0: std (FILE *ptr, int flags, int file, struct _reent *data)
sl@0: #endif
sl@0: {
sl@0:   ptr->_p = 0;
sl@0:   ptr->_r = 0;
sl@0:   ptr->_w = 0;
sl@0:   ptr->_flags = (short)flags;
sl@0:   ptr->_file = (short)file;
sl@0:   ptr->_bf._base = 0;
sl@0:   ptr->_lbfsize = 0;
sl@0:   ptr->_cookie = ptr;
sl@0:   ptr->_read = __sread;
sl@0:   ptr->_write = __swrite;
sl@0:   ptr->_seek = __sseek;
sl@0:   ptr->_close = __sclose;
sl@0:   ptr->_data = data;
sl@0: }
sl@0: 
sl@0: struct _glue *
sl@0: __sfmoreglue (struct _reent *d, register int n)
sl@0: {
sl@0:   struct _glue *g;
sl@0:   FILE *p;
sl@0: 
sl@0:   g = (struct _glue *) _malloc_r (d, sizeof (*g) + n * sizeof (FILE));
sl@0:   if (g == NULL)
sl@0:     return NULL;
sl@0:   p = (FILE *) (g + 1);
sl@0:   g->_next = NULL;
sl@0:   g->_niobs = n;
sl@0:   g->_iobs = p;
sl@0:   memset (p, 0, n * sizeof (FILE));
sl@0:   return g;
sl@0: }
sl@0: 
sl@0: /*
sl@0:  * Find a free FILE for fopen et al.
sl@0:  */
sl@0: 
sl@0: FILE *
sl@0: __sfp (struct _reent *d)
sl@0: {
sl@0:   FILE *fp;
sl@0:   int n;
sl@0:   struct _glue *g;
sl@0: 
sl@0:   if (!d->__sdidinit)
sl@0:     __sinit (d);
sl@0:   for (g = &d->__sglue;; g = g->_next)
sl@0:     {
sl@0:       for (fp = g->_iobs, n = g->_niobs; --n >= 0; fp++)
sl@0: 	if (fp->_flags == 0)
sl@0: 	  goto found;
sl@0:       if (g->_next == NULL &&
sl@0: 	  (g->_next = __sfmoreglue (d, NDYNAMIC)) == NULL)
sl@0: 	break;
sl@0:     }
sl@0:   d->_errno = ENOMEM;
sl@0:   return NULL;
sl@0: 
sl@0: found:
sl@0:   fp->_flags = 1;		/* reserve this slot; caller sets real flags */
sl@0:   fp->_p = NULL;		/* no current pointer */
sl@0:   fp->_w = 0;			/* nothing to read or write */
sl@0:   fp->_r = 0;
sl@0:   fp->_bf._base = NULL;		/* no buffer */
sl@0:   fp->_bf._size = 0;
sl@0:   fp->_lbfsize = 0;		/* not line buffered */
sl@0:   fp->_file = -1;		/* no file */
sl@0:   /* fp->_cookie = <any>; */	/* caller sets cookie, _read/_write etc */
sl@0:   fp->_ub._base = NULL;		/* no ungetc buffer */
sl@0:   fp->_ub._size = 0;
sl@0:   fp->_lb._base = NULL;		/* no line buffer */
sl@0:   fp->_lb._size = 0;
sl@0:   fp->_data = d;
sl@0:   return fp;
sl@0: }
sl@0: 
sl@0: /*
sl@0:  * exit() calls _cleanup() through *__cleanup, set whenever we
sl@0:  * open or buffer a file.  This chicanery is done so that programs
sl@0:  * that do not use stdio need not link it all in.
sl@0:  *
sl@0:  * The name `_cleanup' is, alas, fairly well known outside stdio.
sl@0:  */
sl@0: /**
sl@0: A reentrant version of _cleanup().
sl@0: */
sl@0: EXPORT_C void
sl@0: _cleanup_r (struct _reent *ptr)
sl@0: {
sl@0:   (void) _fwalk(ptr, fclose);
sl@0: }
sl@0: 
sl@0: #ifndef _REENT_ONLY
sl@0: 
sl@0: /**
sl@0: Performs cleanup
sl@0: */
sl@0: EXPORT_C void
sl@0: _cleanup (void)
sl@0: {
sl@0:   _cleanup_r (_REENT);
sl@0: }
sl@0: #endif
sl@0: 
sl@0: /*
sl@0:  * __sinit() is called whenever stdio's internal variables must be set up.
sl@0:  */
sl@0: 
sl@0: void
sl@0: __sinit (struct _reent *s)
sl@0: {
sl@0:   /* make sure we clean up on exit */
sl@0:   s->__cleanup = _cleanup_r;	/* conservative */
sl@0:   s->__sdidinit = 1;
sl@0: 
sl@0: #ifdef __GCCXML__
sl@0:   _std (_stdin_r(s),  __SRD, 0, s);
sl@0:   _std (_stdout_r(s), __SWR, 1, s);
sl@0:   _std (_stderr_r(s), __SWR | __SNBF, 2, s);
sl@0: #else
sl@0:   std (_stdin_r(s),  __SRD, 0, s);
sl@0:   std (_stdout_r(s), __SWR, 1, s);
sl@0:   std (_stderr_r(s), __SWR | __SNBF, 2, s);
sl@0: #endif
sl@0: 
sl@0:   /* initialise the head of the glue chain to cover stdim/stdout/stderr */
sl@0:   s->__sglue._next = NULL;
sl@0:   s->__sglue._niobs = 3;
sl@0:   s->__sglue._iobs = &s->_sf[0];
sl@0: }
sl@0: 
sl@0: /* Function interface to stdin/stdout/stderr 
sl@0:  *
sl@0:  * These functions should return a value which is fixed for any given
sl@0:  * reentrancy context, but it doesn't have to be fixed at compile time,
sl@0:  * and we don't need to have initialised stdio either.
sl@0:  */
sl@0: 
sl@0: /**
sl@0: Function interface to the "constants" stdin.
sl@0: These functions guarantee to return a fixed value, so that it 
sl@0: will be possible to use expressions such as if (fp != stdout) fclose(fp);
sl@0: with complete confidence. Unfortunately it will rule out initialising global
sl@0: variables with stdin/stdout/stderr, as in the common idiom:
sl@0: 
sl@0: static FILE *log = stderr;
sl@0: 
sl@0: This isn't currently possible with EPOC32. 
sl@0: */
sl@0: EXPORT_C FILE *__stdin (void)
sl@0: {
sl@0: 	return _stdin_r(_REENT);
sl@0: }
sl@0: 
sl@0: /**
sl@0: Function interface to the "constants" stdout
sl@0: See __stdin
sl@0: */
sl@0: EXPORT_C FILE *__stdout (void)
sl@0: {
sl@0: 	return _stdout_r(_REENT);
sl@0: }
sl@0: 
sl@0: /**
sl@0: Function interface to the "constants" stderr
sl@0: See __stdin
sl@0: */
sl@0: EXPORT_C FILE *__stderr (void)
sl@0: {
sl@0: 	return _stderr_r(_REENT);
sl@0: }