1/* An fseeko() function that, together with fflush(), is POSIX compliant. 2 Copyright (C) 2007-2014 Free Software Foundation, Inc. 3 4 This program is free software; you can redistribute it and/or modify 5 it under the terms of the GNU General Public License as published by 6 the Free Software Foundation; either version 3, or (at your option) 7 any later version. 8 9 This program is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 GNU General Public License for more details. 13 14 You should have received a copy of the GNU General Public License along 15 with this program; if not, see <http://www.gnu.org/licenses/>. */ 16 17#include <config.h> 18 19/* Specification. */ 20#include <stdio.h> 21 22/* Get off_t, lseek, _POSIX_VERSION. */ 23#include <unistd.h> 24 25#include "stdio-impl.h" 26 27int 28fseeko (FILE *fp, off_t offset, int whence) 29#undef fseeko 30#if !HAVE_FSEEKO 31# undef fseek 32# define fseeko fseek 33#endif 34#if _GL_WINDOWS_64_BIT_OFF_T 35# undef fseeko 36# if HAVE__FSEEKI64 /* msvc, mingw64 */ 37# define fseeko _fseeki64 38# else /* mingw */ 39# define fseeko fseeko64 40# endif 41#endif 42{ 43#if LSEEK_PIPE_BROKEN 44 /* mingw gives bogus answers rather than failure on non-seekable files. */ 45 if (lseek (fileno (fp), 0, SEEK_CUR) == -1) 46 return EOF; 47#endif 48 49 /* These tests are based on fpurge.c. */ 50#if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */ 51 if (fp->_IO_read_end == fp->_IO_read_ptr 52 && fp->_IO_write_ptr == fp->_IO_write_base 53 && fp->_IO_save_base == NULL) 54#elif defined __sferror || defined __DragonFly__ /* FreeBSD, NetBSD, OpenBSD, DragonFly, Mac OS X, Cygwin */ 55# if defined __SL64 && defined __SCLE /* Cygwin */ 56 if ((fp->_flags & __SL64) == 0) 57 { 58 /* Cygwin 1.5.0 through 1.5.24 failed to open stdin in 64-bit 59 mode; but has an fseeko that requires 64-bit mode. */ 60 FILE *tmp = fopen ("/dev/null", "r"); 61 if (!tmp) 62 return -1; 63 fp->_flags |= __SL64; 64 fp->_seek64 = tmp->_seek64; 65 fclose (tmp); 66 } 67# endif 68 if (fp_->_p == fp_->_bf._base 69 && fp_->_r == 0 70 && fp_->_w == ((fp_->_flags & (__SLBF | __SNBF | __SRD)) == 0 /* fully buffered and not currently reading? */ 71 ? fp_->_bf._size 72 : 0) 73 && fp_ub._base == NULL) 74#elif defined __EMX__ /* emx+gcc */ 75 if (fp->_ptr == fp->_buffer 76 && fp->_rcount == 0 77 && fp->_wcount == 0 78 && fp->_ungetc_count == 0) 79#elif defined __minix /* Minix */ 80 if (fp_->_ptr == fp_->_buf 81 && (fp_->_ptr == NULL || fp_->_count == 0)) 82#elif defined _IOERR /* AIX, HP-UX, IRIX, OSF/1, Solaris, OpenServer, mingw, NonStop Kernel */ 83 if (fp_->_ptr == fp_->_base 84 && (fp_->_ptr == NULL || fp_->_cnt == 0)) 85#elif defined __UCLIBC__ /* uClibc */ 86 if (((fp->__modeflags & __FLAG_WRITING) == 0 87 || fp->__bufpos == fp->__bufstart) 88 && ((fp->__modeflags & (__FLAG_READONLY | __FLAG_READING)) == 0 89 || fp->__bufpos == fp->__bufread)) 90#elif defined __QNX__ /* QNX */ 91 if ((fp->_Mode & 0x2000 /* _MWRITE */ ? fp->_Next == fp->_Buf : fp->_Next == fp->_Rend) 92 && fp->_Rback == fp->_Back + sizeof (fp->_Back) 93 && fp->_Rsave == NULL) 94#elif defined __MINT__ /* Atari FreeMiNT */ 95 if (fp->__bufp == fp->__buffer 96 && fp->__get_limit == fp->__bufp 97 && fp->__put_limit == fp->__bufp 98 && !fp->__pushed_back) 99#elif defined EPLAN9 /* Plan9 */ 100 if (fp->rp == fp->buf 101 && fp->wp == fp->buf) 102#elif FUNC_FFLUSH_STDIN < 0 && 200809 <= _POSIX_VERSION 103 /* Cross-compiling to some other system advertising conformance to 104 POSIX.1-2008 or later. Assume fseeko and fflush work as advertised. 105 If this assumption is incorrect, please report the bug to 106 bug-gnulib. */ 107 if (0) 108#else 109 #error "Please port gnulib fseeko.c to your platform! Look at the code in fseeko.c, then report this to bug-gnulib." 110#endif 111 { 112 /* We get here when an fflush() call immediately preceded this one (or 113 if ftell() has created buffers but no I/O has occurred on a 114 newly-opened stream). We know there are no buffers. */ 115 off_t pos = lseek (fileno (fp), offset, whence); 116 if (pos == -1) 117 { 118#if defined __sferror || defined __DragonFly__ /* FreeBSD, NetBSD, OpenBSD, DragonFly, Mac OS X, Cygwin */ 119 fp_->_flags &= ~__SOFF; 120#endif 121 return -1; 122 } 123 124#if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */ 125 fp->_flags &= ~_IO_EOF_SEEN; 126 fp->_offset = pos; 127#elif defined __sferror || defined __DragonFly__ /* FreeBSD, NetBSD, OpenBSD, DragonFly, Mac OS X, Cygwin */ 128# if defined __CYGWIN__ 129 /* fp_->_offset is typed as an integer. */ 130 fp_->_offset = pos; 131# else 132 /* fp_->_offset is an fpos_t. */ 133 { 134 /* Use a union, since on NetBSD, the compilation flags 135 determine whether fpos_t is typedef'd to off_t or a struct 136 containing a single off_t member. */ 137 union 138 { 139 fpos_t f; 140 off_t o; 141 } u; 142 u.o = pos; 143 fp_->_offset = u.f; 144 } 145# endif 146 fp_->_flags |= __SOFF; 147 fp_->_flags &= ~__SEOF; 148#elif defined __EMX__ /* emx+gcc */ 149 fp->_flags &= ~_IOEOF; 150#elif defined _IOERR /* AIX, HP-UX, IRIX, OSF/1, Solaris, OpenServer, mingw, NonStop Kernel */ 151 fp->_flag &= ~_IOEOF; 152#elif defined __MINT__ /* Atari FreeMiNT */ 153 fp->__offset = pos; 154 fp->__eof = 0; 155#endif 156 return 0; 157 } 158 return fseeko (fp, offset, whence); 159} 160