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 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 sl@0: #include sl@0: #include 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 sl@0: #include sl@0: #include sl@0: #include "un-namespace.h" sl@0: #include sl@0: #include 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: }