/* from Dale Schumacher's dLibs */

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>

__EXTERN void _getbuf __PROTO((FILE *));
static FILE *_fopen __PROTO((const char *, const char *, FILE *));

/* lowest character device handle # */
#define	LAST_DEVICE	__SMALLEST_VALID_HANDLE

extern int __default_mode__;

static FILE *_fopen(filename, mode, fp)
	const char *filename;
	const char *mode;
	FILE *fp;
/*
 *	INTERNAL FUNCTION.  Attempt to open <filename> in the given
 *	<mode> and attach it to the stream <fp>
 */
	{
	register int h, i, iomode = 0, f = __default_mode__;

	while(*mode)
		{
		switch(*mode++)
			{
			case 'r':
				f |= _IOREAD;
				break;
			case 'w':
				f |= _IOWRT;
				iomode |= (O_CREAT | O_TRUNC);
				break;
			case 'a':
				f |= _IOWRT;
				iomode |= (O_CREAT | O_APPEND);
				break;
			case '+':
				f &= ~(_IOREAD | _IOWRT);
				f |= _IORW;
				break;
			case 'b':
				f |= _IOBIN;
				break;
			case 't':
				f &= ~_IOBIN;
				break;
			default:
				return(NULL);
			}
		}
	if((i = (f & (_IORW | _IOREAD | _IOWRT))) == 0)
		return(NULL);
	else if(i == _IOREAD)
		iomode |= O_RDONLY;
	else if(i == _IOWRT)
		iomode |= O_WRONLY;
	else
		iomode |= O_RDWR;
	h = open(filename, iomode, 0644);
	if(h < __SMALLEST_VALID_HANDLE)
		{
		return(NULL);		/* file open/create error */
		}
	if(isatty(h))
		f |= (_IODEV | _IOLBF);
	else
		f |= _IOFBF;
	fp->_file = h;			/* file handle */
	fp->_flag = f;			/* file status flags */

	return(fp);
	}

FILE *fopen(filename, mode)
	const char *filename, *mode;
	{
	register int i;
	register FILE *fp = NULL;

	for(i=0; (!fp && (i < _NFILE)); ++i)
		if(!(_iob[i]._flag & (_IORW | _IOREAD | _IOWRT))) 
			fp = &_iob[i]; /* empty slot */
	if(fp != NULL)
	{
		if(_fopen(filename, mode, fp) == NULL)
		    return NULL;
		_getbuf(fp);
		return fp;
	}
	else
	  {
		errno = EMFILE;
		return NULL;
	  }
	}

/*
 * re-coded,  foobared code deleted
 *
 *	++jrb
 */
FILE *freopen(filename, mode, fp)
	const char *filename, *mode;
	FILE *fp;
{
    unsigned int f;
    
    if(fp == NULL) return NULL;
    
    f = fp->_flag;
    if((f & (_IORW | _IOREAD | _IOWRT)) != 0)
    { /* file not closed, close it */
#if 0
        if(fflush(fp) != 0) return NULL;	        /* flush err */
        if(close(fp->_file) != 0) return NULL;		/* close err */
#else
	fflush(fp); close(fp->_file);		/* ANSI says ignore errors */
#endif
    }
    /* save buffer discipline and setbuf settings, and _IOWRT just for
       determinining line buffering after the next _fopen */
    f &= (_IOFBF | _IOLBF | _IONBF | _IOMYBUF | _IOWRT);

    /* open the new file according to mode */
    if((fp = _fopen(filename, mode, fp)) == NULL)
	return NULL;
    if(fp->_flag & _IODEV)
    { /* we are re-opening to a tty */
	if((f & _IOFBF) && (f & _IOWRT) && (f & _IOMYBUF))
	{   /* was a FBF & WRT & !setvbuff'ed  */
	    /* reset to line buffering */
	    f &= ~_IOFBF;
	    f |=  _IOLBF;
	}
    }
    f &= ~_IOWRT; /* get rid of saved _IOWRT flag */
    
    /* put buffering and discipline flags in new fp->_flag */
    fp->_flag &= ~(_IONBF | _IOLBF | _IOFBF | _IOMYBUF);
    fp->_flag |= f;
    
    return fp;
    }
