Bump to m4 1.4.19
[platform/upstream/m4.git] / lib / ftello.c
1 /* An ftello() function that works around platform bugs.
2    Copyright (C) 2007, 2009-2021 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 of the License, or
7    (at your option) 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
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 }