]> git.ipfire.org Git - thirdparty/gcc.git/blob - libstdc++-v3/config/io/basic_file_stdio.cc
PR libstdc++/36104 part four
[thirdparty/gcc.git] / libstdc++-v3 / config / io / basic_file_stdio.cc
1 // Wrapper of C-language FILE struct -*- C++ -*-
2
3 // Copyright (C) 2000, 2001, 2002, 2003, 2004, 2006, 2007, 2009, 2010
4 // Free Software Foundation, Inc.
5 //
6 // This file is part of the GNU ISO C++ Library. This library is free
7 // software; you can redistribute it and/or modify it under the
8 // terms of the GNU General Public License as published by the
9 // Free Software Foundation; either version 3, or (at your option)
10 // any later version.
11
12 // This library is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
16
17 // Under Section 7 of GPL version 3, you are granted additional
18 // permissions described in the GCC Runtime Library Exception, version
19 // 3.1, as published by the Free Software Foundation.
20
21 // You should have received a copy of the GNU General Public License and
22 // a copy of the GCC Runtime Library Exception along with this program;
23 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24 // <http://www.gnu.org/licenses/>.
25
26 //
27 // ISO C++ 14882: 27.8 File-based streams
28 //
29
30 #include <bits/basic_file.h>
31 #include <fcntl.h>
32 #include <errno.h>
33
34 #ifdef _GLIBCXX_HAVE_POLL
35 #include <poll.h>
36 #endif
37
38 // Pick up ioctl on Solaris 2.8
39 #ifdef _GLIBCXX_HAVE_UNISTD_H
40 #include <unistd.h>
41 #endif
42
43 // Pick up FIONREAD on Solaris 2
44 #ifdef _GLIBCXX_HAVE_SYS_IOCTL_H
45 #define BSD_COMP
46 #include <sys/ioctl.h>
47 #endif
48
49 // Pick up FIONREAD on Solaris 2.5.
50 #ifdef _GLIBCXX_HAVE_SYS_FILIO_H
51 #include <sys/filio.h>
52 #endif
53
54 #ifdef _GLIBCXX_HAVE_SYS_UIO_H
55 #include <sys/uio.h>
56 #endif
57
58 #if defined(_GLIBCXX_HAVE_S_ISREG) || defined(_GLIBCXX_HAVE_S_IFREG)
59 # include <sys/stat.h>
60 # ifdef _GLIBCXX_HAVE_S_ISREG
61 # define _GLIBCXX_ISREG(x) S_ISREG(x)
62 # else
63 # define _GLIBCXX_ISREG(x) (((x) & S_IFMT) == S_IFREG)
64 # endif
65 #endif
66
67 #include <limits> // For <off_t>::max() and min() and <streamsize>::max()
68
69 namespace
70 {
71 // Map ios_base::openmode flags to a string for use in fopen().
72 // Table of valid combinations as given in [lib.filebuf.members]/2.
73 static const char*
74 fopen_mode(std::ios_base::openmode mode)
75 {
76 enum
77 {
78 in = std::ios_base::in,
79 out = std::ios_base::out,
80 trunc = std::ios_base::trunc,
81 app = std::ios_base::app,
82 binary = std::ios_base::binary
83 };
84
85 // _GLIBCXX_RESOLVE_LIB_DEFECTS
86 // 596. 27.8.1.3 Table 112 omits "a+" and "a+b" modes.
87 switch (mode & (in|out|trunc|app|binary))
88 {
89 case ( out ): return "w";
90 case ( out |app ): return "a";
91 case ( app ): return "a";
92 case ( out|trunc ): return "w";
93 case (in ): return "r";
94 case (in|out ): return "r+";
95 case (in|out|trunc ): return "w+";
96 case (in|out |app ): return "a+";
97 case (in |app ): return "a+";
98
99 case ( out |binary): return "wb";
100 case ( out |app|binary): return "ab";
101 case ( app|binary): return "ab";
102 case ( out|trunc |binary): return "wb";
103 case (in |binary): return "rb";
104 case (in|out |binary): return "r+b";
105 case (in|out|trunc |binary): return "w+b";
106 case (in|out |app|binary): return "a+b";
107 case (in |app|binary): return "a+b";
108
109 default: return 0; // invalid
110 }
111 }
112
113 // Wrapper handling partial write.
114 static std::streamsize
115 xwrite(int __fd, const char* __s, std::streamsize __n)
116 {
117 std::streamsize __nleft = __n;
118
119 for (;;)
120 {
121 const std::streamsize __ret = write(__fd, __s, __nleft);
122 if (__ret == -1L && errno == EINTR)
123 continue;
124 if (__ret == -1L)
125 break;
126
127 __nleft -= __ret;
128 if (__nleft == 0)
129 break;
130
131 __s += __ret;
132 }
133
134 return __n - __nleft;
135 }
136
137 #ifdef _GLIBCXX_HAVE_WRITEV
138 // Wrapper handling partial writev.
139 static std::streamsize
140 xwritev(int __fd, const char* __s1, std::streamsize __n1,
141 const char* __s2, std::streamsize __n2)
142 {
143 std::streamsize __nleft = __n1 + __n2;
144 std::streamsize __n1_left = __n1;
145
146 struct iovec __iov[2];
147 __iov[1].iov_base = const_cast<char*>(__s2);
148 __iov[1].iov_len = __n2;
149
150 for (;;)
151 {
152 __iov[0].iov_base = const_cast<char*>(__s1);
153 __iov[0].iov_len = __n1_left;
154
155 const std::streamsize __ret = writev(__fd, __iov, 2);
156 if (__ret == -1L && errno == EINTR)
157 continue;
158 if (__ret == -1L)
159 break;
160
161 __nleft -= __ret;
162 if (__nleft == 0)
163 break;
164
165 const std::streamsize __off = __ret - __n1_left;
166 if (__off >= 0)
167 {
168 __nleft -= xwrite(__fd, __s2 + __off, __n2 - __off);
169 break;
170 }
171
172 __s1 += __ret;
173 __n1_left -= __ret;
174 }
175
176 return __n1 + __n2 - __nleft;
177 }
178 #endif
179 } // anonymous namespace
180
181
182 namespace std _GLIBCXX_VISIBILITY(default)
183 {
184 _GLIBCXX_BEGIN_NAMESPACE_VERSION
185
186 // Definitions for __basic_file<char>.
187 __basic_file<char>::__basic_file(__c_lock* /*__lock*/) throw()
188 : _M_cfile(NULL), _M_cfile_created(false) { }
189
190 __basic_file<char>::~__basic_file()
191 { this->close(); }
192
193 __basic_file<char>*
194 __basic_file<char>::sys_open(__c_file* __file, ios_base::openmode)
195 {
196 __basic_file* __ret = NULL;
197 if (!this->is_open() && __file)
198 {
199 int __err;
200 errno = 0;
201 do
202 __err = this->sync();
203 while (__err && errno == EINTR);
204 if (!__err)
205 {
206 _M_cfile = __file;
207 _M_cfile_created = false;
208 __ret = this;
209 }
210 }
211 return __ret;
212 }
213
214 __basic_file<char>*
215 __basic_file<char>::sys_open(int __fd, ios_base::openmode __mode) throw ()
216 {
217 __basic_file* __ret = NULL;
218 const char* __c_mode = fopen_mode(__mode);
219 if (__c_mode && !this->is_open() && (_M_cfile = fdopen(__fd, __c_mode)))
220 {
221 char* __buf = NULL;
222 _M_cfile_created = true;
223 if (__fd == 0)
224 setvbuf(_M_cfile, __buf, _IONBF, 0);
225 __ret = this;
226 }
227 return __ret;
228 }
229
230 __basic_file<char>*
231 __basic_file<char>::open(const char* __name, ios_base::openmode __mode,
232 int /*__prot*/)
233 {
234 __basic_file* __ret = NULL;
235 const char* __c_mode = fopen_mode(__mode);
236 if (__c_mode && !this->is_open())
237 {
238 #ifdef _GLIBCXX_USE_LFS
239 if ((_M_cfile = fopen64(__name, __c_mode)))
240 #else
241 if ((_M_cfile = fopen(__name, __c_mode)))
242 #endif
243 {
244 _M_cfile_created = true;
245 __ret = this;
246 }
247 }
248 return __ret;
249 }
250
251 bool
252 __basic_file<char>::is_open() const throw ()
253 { return _M_cfile != 0; }
254
255 int
256 __basic_file<char>::fd() throw ()
257 { return fileno(_M_cfile); }
258
259 __c_file*
260 __basic_file<char>::file() throw ()
261 { return _M_cfile; }
262
263 __basic_file<char>*
264 __basic_file<char>::close()
265 {
266 __basic_file* __ret = static_cast<__basic_file*>(NULL);
267 if (this->is_open())
268 {
269 int __err = 0;
270 if (_M_cfile_created)
271 {
272 // In general, no need to zero errno in advance if checking
273 // for error first. However, C89/C99 (at variance with IEEE
274 // 1003.1, f.i.) do not mandate that fclose must set errno
275 // upon error.
276 errno = 0;
277 do
278 __err = fclose(_M_cfile);
279 while (__err && errno == EINTR);
280 }
281 _M_cfile = 0;
282 if (!__err)
283 __ret = this;
284 }
285 return __ret;
286 }
287
288 streamsize
289 __basic_file<char>::xsgetn(char* __s, streamsize __n)
290 {
291 streamsize __ret;
292 do
293 __ret = read(this->fd(), __s, __n);
294 while (__ret == -1L && errno == EINTR);
295 return __ret;
296 }
297
298 streamsize
299 __basic_file<char>::xsputn(const char* __s, streamsize __n)
300 { return xwrite(this->fd(), __s, __n); }
301
302 streamsize
303 __basic_file<char>::xsputn_2(const char* __s1, streamsize __n1,
304 const char* __s2, streamsize __n2)
305 {
306 streamsize __ret = 0;
307 #ifdef _GLIBCXX_HAVE_WRITEV
308 __ret = xwritev(this->fd(), __s1, __n1, __s2, __n2);
309 #else
310 if (__n1)
311 __ret = xwrite(this->fd(), __s1, __n1);
312
313 if (__ret == __n1)
314 __ret += xwrite(this->fd(), __s2, __n2);
315 #endif
316 return __ret;
317 }
318
319 streamoff
320 __basic_file<char>::seekoff(streamoff __off, ios_base::seekdir __way) throw ()
321 {
322 #ifdef _GLIBCXX_USE_LFS
323 return lseek64(this->fd(), __off, __way);
324 #else
325 if (__off > numeric_limits<off_t>::max()
326 || __off < numeric_limits<off_t>::min())
327 return -1L;
328 return lseek(this->fd(), __off, __way);
329 #endif
330 }
331
332 int
333 __basic_file<char>::sync()
334 { return fflush(_M_cfile); }
335
336 streamsize
337 __basic_file<char>::showmanyc()
338 {
339 #ifndef _GLIBCXX_NO_IOCTL
340 #ifdef FIONREAD
341 // Pipes and sockets.
342 #ifdef _GLIBCXX_FIONREAD_TAKES_OFF_T
343 off_t __num = 0;
344 #else
345 int __num = 0;
346 #endif
347 int __r = ioctl(this->fd(), FIONREAD, &__num);
348 if (!__r && __num >= 0)
349 return __num;
350 #endif
351 #endif
352
353 #ifdef _GLIBCXX_HAVE_POLL
354 // Cheap test.
355 struct pollfd __pfd[1];
356 __pfd[0].fd = this->fd();
357 __pfd[0].events = POLLIN;
358 if (poll(__pfd, 1, 0) <= 0)
359 return 0;
360 #endif
361
362 #if defined(_GLIBCXX_HAVE_S_ISREG) || defined(_GLIBCXX_HAVE_S_IFREG)
363 // Regular files.
364 #ifdef _GLIBCXX_USE_LFS
365 struct stat64 __buffer;
366 const int __err = fstat64(this->fd(), &__buffer);
367 if (!__err && _GLIBCXX_ISREG(__buffer.st_mode))
368 {
369 const streamoff __off = __buffer.st_size - lseek64(this->fd(), 0,
370 ios_base::cur);
371 return std::min(__off, streamoff(numeric_limits<streamsize>::max()));
372 }
373 #else
374 struct stat __buffer;
375 const int __err = fstat(this->fd(), &__buffer);
376 if (!__err && _GLIBCXX_ISREG(__buffer.st_mode))
377 return __buffer.st_size - lseek(this->fd(), 0, ios_base::cur);
378 #endif
379 #endif
380 return 0;
381 }
382
383 _GLIBCXX_END_NAMESPACE_VERSION
384 } // namespace
385