diff options
Diffstat (limited to 'contrib/libstdc++/config/io/basic_file_stdio.cc')
-rw-r--r-- | contrib/libstdc++/config/io/basic_file_stdio.cc | 305 |
1 files changed, 191 insertions, 114 deletions
diff --git a/contrib/libstdc++/config/io/basic_file_stdio.cc b/contrib/libstdc++/config/io/basic_file_stdio.cc index 5393a14..a3ed839 100644 --- a/contrib/libstdc++/config/io/basic_file_stdio.cc +++ b/contrib/libstdc++/config/io/basic_file_stdio.cc @@ -1,6 +1,6 @@ // Wrapper of C-language FILE struct -*- C++ -*- -// Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc. +// Copyright (C) 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. // // This file is part of the GNU ISO C++ Library. This library is free // software; you can redistribute it and/or modify it under the @@ -33,87 +33,156 @@ #include <bits/basic_file.h> #include <fcntl.h> +#include <errno.h> + +#ifdef _GLIBCXX_HAVE_POLL +#include <poll.h> +#endif + +// Pick up ioctl on Solaris 2.8 +#ifdef _GLIBCXX_HAVE_UNISTD_H #include <unistd.h> +#endif -#ifdef _GLIBCPP_HAVE_SYS_IOCTL_H -#define BSD_COMP /* Get FIONREAD on Solaris2. */ +// Pick up FIONREAD on Solaris 2 +#ifdef _GLIBCXX_HAVE_SYS_IOCTL_H +#define BSD_COMP #include <sys/ioctl.h> #endif // Pick up FIONREAD on Solaris 2.5. -#ifdef _GLIBCPP_HAVE_SYS_FILIO_H +#ifdef _GLIBCXX_HAVE_SYS_FILIO_H #include <sys/filio.h> #endif -#ifdef _GLIBCPP_HAVE_POLL -#include <poll.h> +#ifdef _GLIBCXX_HAVE_SYS_UIO_H +#include <sys/uio.h> #endif -#if defined(_GLIBCPP_HAVE_S_ISREG) || defined(_GLIBCPP_HAVE_S_IFREG) +#if defined(_GLIBCXX_HAVE_S_ISREG) || defined(_GLIBCXX_HAVE_S_IFREG) # include <sys/stat.h> -# ifdef _GLIBCPP_HAVE_S_ISREG -# define _GLIBCPP_ISREG(x) S_ISREG(x) +# ifdef _GLIBCXX_HAVE_S_ISREG +# define _GLIBCXX_ISREG(x) S_ISREG(x) # else -# define _GLIBCPP_ISREG(x) (((x) & S_IFMT) == S_IFREG) +# define _GLIBCXX_ISREG(x) (((x) & S_IFMT) == S_IFREG) # endif #endif -namespace std -{ - // Definitions for __basic_file<char>. - __basic_file<char>::__basic_file(__c_lock* /*__lock*/) - : _M_cfile(NULL), _M_cfile_created(false) { } +#include <limits> // For <off_t>::max() and min() - __basic_file<char>::~__basic_file() - { this->close(); } - - void - __basic_file<char>::_M_open_mode(ios_base::openmode __mode, int& __p_mode, - int&, char* __c_mode) - { - bool __testb = __mode & ios_base::binary; - bool __testi = __mode & ios_base::in; - bool __testo = __mode & ios_base::out; - bool __testt = __mode & ios_base::trunc; - bool __testa = __mode & ios_base::app; - - // Set __c_mode for use in fopen. - // Set __p_mode for use in open. - if (!__testi && __testo && !__testt && !__testa) - { - strcpy(__c_mode, "w"); - __p_mode = (O_WRONLY | O_CREAT); - } - if (!__testi && __testo && !__testt && __testa) +namespace __gnu_internal +{ + // Map ios_base::openmode flags to a string for use in fopen(). + // Table of valid combinations as given in [lib.filebuf.members]/2. + static const char* + fopen_mode(std::ios_base::openmode mode) + { + enum { - strcpy(__c_mode, "a"); - __p_mode |= O_WRONLY | O_CREAT | O_APPEND; - } - if (!__testi && __testo && __testt && !__testa) + in = std::ios_base::in, + out = std::ios_base::out, + trunc = std::ios_base::trunc, + app = std::ios_base::app, + binary = std::ios_base::binary + }; + + switch (mode & (in|out|trunc|app|binary)) { - strcpy(__c_mode, "w"); - __p_mode |= O_WRONLY | O_CREAT | O_TRUNC; + case ( out ): return "w"; + case ( out |app ): return "a"; + case ( out|trunc ): return "w"; + case (in ): return "r"; + case (in|out ): return "r+"; + case (in|out|trunc ): return "w+"; + + case ( out |binary): return "wb"; + case ( out |app|binary): return "ab"; + case ( out|trunc |binary): return "wb"; + case (in |binary): return "rb"; + case (in|out |binary): return "r+b"; + case (in|out|trunc |binary): return "w+b"; + + default: return 0; // invalid } + } - if (__testi && !__testo && !__testt && !__testa) - { - strcpy(__c_mode, "r"); - __p_mode |= O_RDONLY; - } - if (__testi && __testo && !__testt && !__testa) + // Wrapper handling partial write. + static std::streamsize + xwrite(int __fd, const char* __s, std::streamsize __n) + { + std::streamsize __nleft = __n; + + for (;;) { - strcpy(__c_mode, "r+"); - __p_mode |= O_RDWR | O_CREAT; + const std::streamsize __ret = write(__fd, __s, __nleft); + if (__ret == -1L && errno == EINTR) + continue; + if (__ret == -1L) + break; + + __nleft -= __ret; + if (__nleft == 0) + break; + + __s += __ret; } - if (__testi && __testo && __testt && !__testa) + + return __n - __nleft; + } + +#ifdef _GLIBCXX_HAVE_WRITEV + // Wrapper handling partial writev. + static std::streamsize + xwritev(int __fd, const char* __s1, std::streamsize __n1, + const char* __s2, std::streamsize __n2) + { + std::streamsize __nleft = __n1 + __n2; + std::streamsize __n1_left = __n1; + + struct iovec __iov[2]; + __iov[1].iov_base = const_cast<char*>(__s2); + __iov[1].iov_len = __n2; + + for (;;) { - strcpy(__c_mode, "w+"); - __p_mode |= O_RDWR | O_CREAT | O_TRUNC; + __iov[0].iov_base = const_cast<char*>(__s1); + __iov[0].iov_len = __n1_left; + + const std::streamsize __ret = writev(__fd, __iov, 2); + if (__ret == -1L && errno == EINTR) + continue; + if (__ret == -1L) + break; + + __nleft -= __ret; + if (__nleft == 0) + break; + + const std::streamsize __off = __ret - __n1_left; + if (__off >= 0) + { + __nleft -= xwrite(__fd, __s2 + __off, __n2 - __off); + break; + } + + __s1 += __ret; + __n1_left -= __ret; } - if (__testb) - strcat(__c_mode, "b"); + + return __n1 + __n2 - __nleft; } - +#endif +} // namespace __gnu_internal + +namespace std +{ + // Definitions for __basic_file<char>. + __basic_file<char>::__basic_file(__c_lock* /*__lock*/) + : _M_cfile(NULL), _M_cfile_created(false) { } + + __basic_file<char>::~__basic_file() + { this->close(); } + __basic_file<char>* __basic_file<char>::sys_open(__c_file* __file, ios_base::openmode) { @@ -122,56 +191,41 @@ namespace std { _M_cfile = __file; _M_cfile_created = false; + this->sync(); __ret = this; } return __ret; } __basic_file<char>* - __basic_file<char>::sys_open(int __fd, ios_base::openmode __mode, - bool __del) + __basic_file<char>::sys_open(int __fd, ios_base::openmode __mode) { __basic_file* __ret = NULL; - int __p_mode = 0; - int __rw_mode = 0; - char __c_mode[4]; - - _M_open_mode(__mode, __p_mode, __rw_mode, __c_mode); - if (!this->is_open() && (_M_cfile = fdopen(__fd, __c_mode))) + const char* __c_mode = __gnu_internal::fopen_mode(__mode); + if (__c_mode && !this->is_open() && (_M_cfile = fdopen(__fd, __c_mode))) { - // Iff __del is true, then close will fclose the fd. - _M_cfile_created = __del; - + char* __buf = NULL; + _M_cfile_created = true; if (__fd == 0) - setvbuf(_M_cfile, reinterpret_cast<char*>(NULL), _IONBF, 0); - + setvbuf(_M_cfile, __buf, _IONBF, 0); __ret = this; } return __ret; } - - int - __basic_file<char>::sys_getc() - { return getc(_M_cfile); } - - int - __basic_file<char>::sys_ungetc(int __c) - { return ungetc(__c, _M_cfile); } __basic_file<char>* __basic_file<char>::open(const char* __name, ios_base::openmode __mode, int /*__prot*/) { __basic_file* __ret = NULL; - int __p_mode = 0; - int __rw_mode = 0; - char __c_mode[4]; - - _M_open_mode(__mode, __p_mode, __rw_mode, __c_mode); - - if (!this->is_open()) + const char* __c_mode = __gnu_internal::fopen_mode(__mode); + if (__c_mode && !this->is_open()) { +#ifdef _GLIBCXX_USE_LFS + if ((_M_cfile = fopen64(__name, __c_mode))) +#else if ((_M_cfile = fopen(__name, __c_mode))) +#endif { _M_cfile_created = true; __ret = this; @@ -186,69 +240,92 @@ namespace std int __basic_file<char>::fd() - { return fileno(_M_cfile) ; } + { return fileno(_M_cfile); } + + __c_file* + __basic_file<char>::file() + { return _M_cfile; } __basic_file<char>* __basic_file<char>::close() { - __basic_file* __retval = static_cast<__basic_file*>(NULL); + __basic_file* __ret = static_cast<__basic_file*>(NULL); if (this->is_open()) { if (_M_cfile_created) fclose(_M_cfile); else - fflush(_M_cfile); + this->sync(); _M_cfile = 0; - __retval = this; + __ret = this; } - return __retval; + return __ret; } streamsize __basic_file<char>::xsgetn(char* __s, streamsize __n) - { return fread(__s, 1, __n, _M_cfile); } - + { + streamsize __ret; + do + __ret = read(this->fd(), __s, __n); + while (__ret == -1L && errno == EINTR); + return __ret; + } + streamsize __basic_file<char>::xsputn(const char* __s, streamsize __n) - { return fwrite(__s, 1, __n, _M_cfile); } - - streamoff - __basic_file<char>::seekoff(streamoff __off, ios_base::seekdir __way, - ios_base::openmode /*__mode*/) - { - if (!fseek(_M_cfile, __off, __way)) - return ftell(_M_cfile); - else - // Fseek failed. - return -1L; + { return __gnu_internal::xwrite(this->fd(), __s, __n); } + + streamsize + __basic_file<char>::xsputn_2(const char* __s1, streamsize __n1, + const char* __s2, streamsize __n2) + { + streamsize __ret = 0; +#ifdef _GLIBCXX_HAVE_WRITEV + __ret = __gnu_internal::xwritev(this->fd(), __s1, __n1, __s2, __n2); +#else + if (__n1) + __ret = __gnu_internal::xwrite(this->fd(), __s1, __n1); + + if (__ret == __n1) + __ret += __gnu_internal::xwrite(this->fd(), __s2, __n2); +#endif + return __ret; } streamoff - __basic_file<char>::seekpos(streamoff __pos, ios_base::openmode /*__mode*/) - { - if (!fseek(_M_cfile, __pos, ios_base::beg)) - return ftell(_M_cfile); - else - // Fseek failed. + __basic_file<char>::seekoff(streamoff __off, ios_base::seekdir __way) + { +#ifdef _GLIBCXX_USE_LFS + return lseek64(this->fd(), __off, __way); +#else + if (__off > std::numeric_limits<off_t>::max() + || __off < std::numeric_limits<off_t>::min()) return -1L; + return lseek(this->fd(), __off, __way); +#endif } - + int __basic_file<char>::sync() { return fflush(_M_cfile); } streamsize - __basic_file<char>::showmanyc_helper() + __basic_file<char>::showmanyc() { #ifdef FIONREAD // Pipes and sockets. +#ifdef _GLIBCXX_FIONREAD_TAKES_OFF_T + off_t __num = 0; +#else int __num = 0; +#endif int __r = ioctl(this->fd(), FIONREAD, &__num); if (!__r && __num >= 0) return __num; #endif -#ifdef _GLIBCPP_HAVE_POLL +#ifdef _GLIBCXX_HAVE_POLL // Cheap test. struct pollfd __pfd[1]; __pfd[0].fd = this->fd(); @@ -257,12 +334,12 @@ namespace std return 0; #endif -#if defined(_GLIBCPP_HAVE_S_ISREG) || defined(_GLIBCPP_HAVE_S_IFREG) +#if defined(_GLIBCXX_HAVE_S_ISREG) || defined(_GLIBCXX_HAVE_S_IFREG) // Regular files. struct stat __buffer; int __ret = fstat(this->fd(), &__buffer); - if (!__ret && _GLIBCPP_ISREG(__buffer.st_mode)) - return __buffer.st_size - ftell(_M_cfile); + if (!__ret && _GLIBCXX_ISREG(__buffer.st_mode)) + return __buffer.st_size - lseek(this->fd(), 0, ios_base::cur); #endif return 0; } |