Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

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