root/maint/gnulib/lib/ftello.c

/* [previous][next][first][last][top][bottom][index][help] */
   1 /* An ftello() function that works around platform bugs.
   2    Copyright (C) 2007, 2009-2021 Free Software Foundation, Inc.
   3 
   4    This file is free software: you can redistribute it and/or modify
   5    it under the terms of the GNU Lesser General Public License as
   6    published by the Free Software Foundation; either version 2.1 of the
   7    License, or (at your option) any later version.
   8 
   9    This file 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 Lesser General Public License for more details.
  13 
  14    You should have received a copy of the GNU Lesser General Public License
  15    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
  16 
  17 #include <config.h>
  18 
  19 /* Specification.  */
  20 #include <stdio.h>
  21 
  22 #include <errno.h>
  23 #include "intprops.h"
  24 
  25 /* Get lseek.  */
  26 #include <unistd.h>
  27 
  28 #include "stdio-impl.h"
  29 
  30 off_t
  31 ftello (FILE *fp)
  32 #undef ftello
  33 #if !HAVE_FTELLO
  34 # undef ftell
  35 # define ftello ftell
  36 #endif
  37 #if _GL_WINDOWS_64_BIT_OFF_T
  38 # undef ftello
  39 # if HAVE__FTELLI64 /* msvc, mingw64 */
  40 #  define ftello _ftelli64
  41 # else /* mingw */
  42 #  define ftello ftello64
  43 # endif
  44 #endif
  45 {
  46 #if FTELLO_BROKEN_AFTER_UNGETC /* macOS >= 10.15 */
  47   /* The system's ftello() is completely broken, because it calls __sflush,
  48      which makes side effects on the stream.  */
  49 
  50   /* Handle non-seekable files first.  */
  51   if (fp->_file < 0 || fp->_seek == NULL)
  52     {
  53       errno = ESPIPE;
  54       return -1;
  55     }
  56 
  57   /* Determine the current offset, ignoring buffered and pushed-back bytes.  */
  58   off_t pos;
  59 
  60   if (fp->_flags & __SOFF)
  61     pos = fp->_offset;
  62   else
  63     {
  64       pos = fp->_seek (fp->_cookie, 0, SEEK_CUR);
  65       if (pos < 0)
  66         return -1;
  67       if (fp->_flags & __SOPT)
  68         {
  69           fp->_offset = pos;
  70           fp->_flags |= __SOFF;
  71         }
  72     }
  73 
  74   if (fp->_flags & __SRD)
  75     {
  76       /* Now consider buffered and pushed-back bytes from ungetc.  */
  77       if (fp->_ub._base != NULL)
  78         /* Considering the buffered bytes, we are at position
  79              pos - fp->_ur.
  80            Considering also the pushed-back bytes, we are at position
  81              pos - fp->_ur - fp->_r.  */
  82         pos = pos - fp->_ur - fp->_r;
  83       else
  84         /* Considering the buffered bytes, we are at position
  85              pos - fp->_r.  */
  86         pos = pos - fp->_r;
  87       if (pos < 0)
  88         {
  89           errno = EIO;
  90           return -1;
  91         }
  92     }
  93   else if ((fp->_flags & __SWR) && fp->_p != NULL)
  94     {
  95       /* Consider the buffered bytes.  */
  96       off_t buffered = fp->_p - fp->_bf._base;
  97 
  98       /* Compute pos + buffered, with overflow check.  */
  99       off_t sum;
 100       if (! INT_ADD_OK (pos, buffered, &sum))
 101         {
 102           errno = EOVERFLOW;
 103           return -1;
 104         }
 105       pos = sum;
 106     }
 107 
 108   return pos;
 109 
 110 #else
 111 
 112 # if LSEEK_PIPE_BROKEN
 113   /* mingw gives bogus answers rather than failure on non-seekable files.  */
 114   if (lseek (fileno (fp), 0, SEEK_CUR) == -1)
 115     return -1;
 116 # endif
 117 
 118 # if FTELLO_BROKEN_AFTER_SWITCHING_FROM_READ_TO_WRITE /* Solaris */
 119   /* The Solaris stdio leaves the _IOREAD flag set after reading from a file
 120      reaches EOF and the program then starts writing to the file.  ftello
 121      gets confused by this.  */
 122   if (fp_->_flag & _IOWRT)
 123     {
 124       off_t pos;
 125 
 126       /* Call ftello nevertheless, for the side effects that it does on fp.  */
 127       ftello (fp);
 128 
 129       /* Compute the file position ourselves.  */
 130       pos = lseek (fileno (fp), (off_t) 0, SEEK_CUR);
 131       if (pos >= 0)
 132         {
 133           if ((fp_->_flag & _IONBF) == 0 && fp_->_base != NULL)
 134             pos += fp_->_ptr - fp_->_base;
 135         }
 136       return pos;
 137     }
 138 # endif
 139 
 140 # if defined __SL64 && defined __SCLE /* Cygwin */
 141   if ((fp->_flags & __SL64) == 0)
 142     {
 143       /* Cygwin 1.5.0 through 1.5.24 failed to open stdin in 64-bit
 144          mode; but has an ftello that requires 64-bit mode.  */
 145       FILE *tmp = fopen ("/dev/null", "r");
 146       if (!tmp)
 147         return -1;
 148       fp->_flags |= __SL64;
 149       fp->_seek64 = tmp->_seek64;
 150       fclose (tmp);
 151     }
 152 # endif
 153 
 154   return ftello (fp);
 155 
 156 #endif
 157 }

/* [previous][next][first][last][top][bottom][index][help] */