sl@0: /*-
sl@0:  * Copyright (c) 1990, 1993
sl@0:  *	The Regents of the University of California.  All rights reserved.
sl@0:  *
sl@0:  * This code is derived from software contributed to Berkeley by
sl@0:  * Chris Torek.
sl@0:  *
sl@0:  * Redistribution and use in source and binary forms, with or without
sl@0:  * modification, are permitted provided that the following conditions
sl@0:  * are met:
sl@0:  * 1. Redistributions of source code must retain the above copyright
sl@0:  *    notice, this list of conditions and the following disclaimer.
sl@0:  * 2. Redistributions in binary form must reproduce the above copyright
sl@0:  *    notice, this list of conditions and the following disclaimer in the
sl@0:  *    documentation and/or other materials provided with the distribution.
sl@0:  * 4. Neither the name of the University nor the names of its contributors
sl@0:  *    may be used to endorse or promote products derived from this software
sl@0:  *    without specific prior written permission.
sl@0:  *
sl@0:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
sl@0:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
sl@0:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
sl@0:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
sl@0:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
sl@0:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
sl@0:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
sl@0:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
sl@0:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
sl@0:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
sl@0:  * SUCH DAMAGE.
sl@0:  * © Portions copyright (c) 2005 - 2006 Nokia Corporation.  All rights reserved.
sl@0:  */
sl@0: 
sl@0: #if defined(LIBC_SCCS) && !defined(lint)
sl@0: static char sccsid[] = "@(#)freopen.c	8.1 (Berkeley) 6/4/93";
sl@0: #endif /* LIBC_SCCS and not lint */
sl@0: #include <sys/cdefs.h>
sl@0: #ifndef __SYMBIAN32__
sl@0: __FBSDID("$FreeBSD: src/lib/libc/stdio/freopen.c,v 1.13 2004/05/22 15:19:41 tjr Exp $");
sl@0: #endif
sl@0: #include "namespace.h"
sl@0: #include <sys/types.h>
sl@0: #include <sys/stat.h>
sl@0: #include <wchar.h>
sl@0: #ifndef DEFFILEMODE
sl@0: #define	DEFFILEMODE	(S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)
sl@0: #endif
sl@0: #include <errno.h>
sl@0: #include <stdio.h>
sl@0: #include <stdlib.h>
sl@0: #include "un-namespace.h"
sl@0: #include <fcntl.h>
sl@0: #include <unistd.h>
sl@0: #include "libc_private.h"
sl@0: #include "local.h"
sl@0: #include "common_def.h"
sl@0: #if (defined(__SYMBIAN32__) && (defined(__WINSCW__) || defined(__WINS__)))
sl@0: #include "libc_wsd_defs.h"
sl@0: #endif
sl@0: 
sl@0: #ifdef EMULATOR
sl@0: int *GET_WSD_VAR_NAME(__sdidinit, g)();
sl@0: #define __sdidinit (*GET_WSD_VAR_NAME(__sdidinit, g)())
sl@0: #endif //EMULATOR
sl@0: /*
sl@0:   Re-direct an existing, open (probably) file to some other file.
sl@0:   ANSI is written such that the original file gets closed if at
sl@0:   all possible, no matter what.
sl@0:  */
sl@0: 
sl@0: EXPORT_C FILE * wfreopen(const wchar_t *  file, const wchar_t *  mode,	FILE *fp)	
sl@0: {
sl@0: 	int f;
sl@0: 	int dflags, flags, isopen, oflags, sverrno, wantfd;
sl@0: 	char destmode[4];
sl@0: 	size_t siz;
sl@0:        
sl@0: 	destmode[0] = '\0';
sl@0:     if(mode==NULL)
sl@0:     {
sl@0:     	errno = EINVAL;
sl@0: 	    (void) fclose(fp);
sl@0: 		return (NULL);
sl@0:     }
sl@0: 	siz = wcstombs(destmode, mode, 4);	
sl@0: 	   
sl@0:       
sl@0: 	if ((flags = __sflags(destmode, &oflags)) == 0) {
sl@0: 		(void) fclose(fp);
sl@0: 		return (NULL);
sl@0: 	}
sl@0: 
sl@0: 	FLOCKFILE(fp);
sl@0: 
sl@0: 	if (!__sdidinit)
sl@0: 		__sinit();
sl@0: 
sl@0: 	/*
sl@0: 	 * If the filename is a NULL pointer, the caller is asking us to
sl@0: 	 * re-open the same file with a different mode. We allow this only
sl@0: 	 * if the modes are compatible.
sl@0: 	 */
sl@0: 	if (file == NULL) {
sl@0: 		/* See comment below regarding freopen() of closed files. */
sl@0: 		if (fp->_flags == 0) {
sl@0: 			FUNLOCKFILE(fp);
sl@0: 			errno = EINVAL;
sl@0: 			return (NULL);
sl@0: 		}
sl@0: 		if ((dflags = _fcntl(fp->_file, F_GETFL)) < 0) {
sl@0: 			sverrno = errno;
sl@0: 			fclose(fp);
sl@0: 			FUNLOCKFILE(fp);
sl@0: 			errno = sverrno;
sl@0: 			return (NULL);
sl@0: 		}
sl@0: 		if ((dflags & O_ACCMODE) != O_RDWR && (dflags & O_ACCMODE) !=
sl@0: 		    (oflags & O_ACCMODE)) {
sl@0: 			fclose(fp);
sl@0: 			FUNLOCKFILE(fp);
sl@0: 			errno = EINVAL;
sl@0: 			return (NULL);
sl@0: 		}
sl@0: 		if ((oflags ^ dflags) & O_APPEND) {
sl@0: 			dflags &= ~O_APPEND;
sl@0: 			dflags |= oflags & O_APPEND;
sl@0: 			if (_fcntl(fp->_file, F_SETFL, dflags) < 0) {
sl@0: 				sverrno = errno;
sl@0: 				fclose(fp);
sl@0: 				FUNLOCKFILE(fp);
sl@0: 				errno = sverrno;
sl@0: 				return (NULL);
sl@0: 			}
sl@0: 		}
sl@0: 		if (oflags & O_TRUNC)
sl@0: 			ftruncate(fp->_file, 0);
sl@0: 		if (_fseeko(fp, 0, oflags & O_APPEND ? SEEK_END : SEEK_SET,
sl@0: 		    0) < 0 && errno != ESPIPE) {
sl@0: 			sverrno = errno;
sl@0: 			fclose(fp);
sl@0: 			FUNLOCKFILE(fp);
sl@0: 			errno = sverrno;
sl@0: 			return (NULL);
sl@0: 		}
sl@0: 		f = fp->_file;
sl@0: 		isopen = 0;
sl@0: 		wantfd = -1;
sl@0: 		
sl@0: 	}
sl@0: 	else
sl@0: 	{
sl@0: 	/*
sl@0: 	 * There are actually programs that depend on being able to "freopen"
sl@0: 	 * descriptors that weren't originally open.  Keep this from breaking.
sl@0: 	 * Remember whether the stream was open to begin with, and which file
sl@0: 	 * descriptor (if any) was associated with it.  If it was attached to
sl@0: 	 * a descriptor, defer closing it; freopen("/dev/stdin", "r", stdin)
sl@0: 	 * should work.  This is unnecessary if it was not a Unix file.
sl@0: 	 */
sl@0: 		if (fp->_flags == 0) {
sl@0: 		fp->_flags = __SEOF;	/* hold on to it */
sl@0: 		isopen = 0;
sl@0: 		wantfd = -1;
sl@0: 		} 
sl@0: 		else {
sl@0: 		/* flush the stream; ANSI doesn't require this. */
sl@0: 		if (fp->_flags & __SWR)
sl@0: 			(void) __sflush(fp);
sl@0: 		/* if close is NULL, closing is a no-op, hence pointless */
sl@0: 		isopen = fp->_close != NULL;
sl@0: 		if ((wantfd = fp->_file) < 0 && isopen) {
sl@0: 			(void) (*fp->_close)(fp->_cookie);
sl@0: 			isopen = 0;
sl@0: 			}
sl@0: 		}
sl@0: 	/* Get a new descriptor to refer to the new file. */
sl@0: 		f = wopen(file, oflags, DEFFILEMODE);
sl@0: 		if (f < 0 && isopen) {
sl@0: 		/* If out of fd's close the old one and try again. */
sl@0: 		if (errno == ENFILE || errno == EMFILE) {
sl@0: 			(void) (*fp->_close)(fp->_cookie);
sl@0: 			isopen = 0;
sl@0: 			f = wopen(file, oflags, DEFFILEMODE);        
sl@0: 			}
sl@0: 		}
sl@0: 		sverrno = errno;
sl@0: 	}
sl@0: 
sl@0: 	/*
sl@0: 	 * Finish closing fp.  Even if the open succeeded above, we cannot
sl@0: 	 * keep fp->_base: it may be the wrong size.  This loses the effect
sl@0: 	 * of any setbuffer calls, but stdio has always done this before.
sl@0: 	 */
sl@0: 	if (isopen)                                      
sl@0: 		(void) (*fp->_close)(fp->_cookie);
sl@0: 	if (fp->_flags & __SMBF)
sl@0: 		{
sl@0: #ifdef __SYMBIAN32__
sl@0: 		BackendFree((char *)fp->_bf._base);
sl@0: #else
sl@0: 		free((char *)fp->_bf._base);
sl@0: #endif//__SYMBIAN32__
sl@0: 		}
sl@0: 		
sl@0: 	fp->_w = 0;
sl@0: 	fp->_r = 0;
sl@0: 	fp->_p = NULL;
sl@0: 	fp->_bf._base = NULL;
sl@0: 	fp->_bf._size = 0;
sl@0: 	fp->_lbfsize = 0;
sl@0: 	if (HASUB(fp))
sl@0: 		FREEUB(fp);
sl@0: 	fp->_ub._size = 0;
sl@0: 	if (HASLB(fp))
sl@0: 		FREELB(fp);
sl@0: 	fp->_lb._size = 0;
sl@0: 	fp->_extra->orientation = 0;
sl@0: 	memset(&fp->_extra->mbstate, 0, sizeof(mbstate_t));
sl@0: 
sl@0: 	if (f < 0) {			/* did not get it after all */
sl@0: 		fp->_flags = 0;		/* set it free */
sl@0: 		errno = sverrno;	/* restore in case _close clobbered */
sl@0: 		FUNLOCKFILE(fp);
sl@0: 		return (NULL);
sl@0: 	}
sl@0: #ifndef __SYMBIAN32__	
sl@0: 	/*
sl@0: 	 * If reopening something that was open before on a real file, try
sl@0: 	 * to maintain the descriptor.  Various C library routines (perror)
sl@0: 	 * assume stderr is always fd STDERR_FILENO, even if being freopen'd.
sl@0: 	 */
sl@0: 	if (wantfd >= 0 && f != wantfd) {
sl@0: 		if (dup2(f, wantfd) >= 0) {
sl@0: 			(void)_close(f);
sl@0: 			f = wantfd;
sl@0: 		}
sl@0: 	}
sl@0: #else
sl@0: 		if (wantfd >= 0 && f > wantfd){
sl@0: 			if (dup2(f, wantfd) >= 0) {
sl@0: 				(void)_close(f);
sl@0: 				f = wantfd;		
sl@0: 		}
sl@0: 	}
sl@0: #endif	
sl@0: 
sl@0: 	fp->_flags = flags;
sl@0: 	fp->_file = f;
sl@0: 	fp->_cookie = fp;
sl@0: 	fp->_read = __sread;
sl@0: 	fp->_write = __swrite;
sl@0: 	fp->_seek = __sseek;
sl@0: 	fp->_close = __sclose;
sl@0: #ifdef __SYMBIAN32__    
sl@0:     if (oflags & O_TEXT) {
sl@0:         fp->_extra->fmode = 't';
sl@0:     }
sl@0:     else {
sl@0:         fp->_extra->fmode = 'b';
sl@0:     }
sl@0: #endif
sl@0: 	FUNLOCKFILE(fp);
sl@0: 	return (fp);
sl@0: }