Home | History | Annotate | Download | only in ext
      1 // Iostreams wrapper for stdio FILE* -*- C++ -*-
      2 
      3 // Copyright (C) 2003-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 /** @file ext/stdio_sync_filebuf.h
     26  *  This file is a GNU extension to the Standard C++ Library.
     27  */
     28 
     29 #ifndef _STDIO_SYNC_FILEBUF_H
     30 #define _STDIO_SYNC_FILEBUF_H 1
     31 
     32 #pragma GCC system_header
     33 
     34 #include <streambuf>
     35 #include <unistd.h>
     36 #include <cstdio>
     37 #include <bits/c++io.h>  // For __c_file
     38 
     39 #ifdef _GLIBCXX_USE_WCHAR_T
     40 #include <cwchar>
     41 #endif
     42 
     43 namespace __gnu_cxx _GLIBCXX_VISIBILITY(default)
     44 {
     45 _GLIBCXX_BEGIN_NAMESPACE_VERSION
     46 
     47   /**
     48    *  @brief Provides a layer of compatibility for C.
     49    *  @ingroup io
     50    *
     51    *  This GNU extension provides extensions for working with standard
     52    *  C FILE*'s.  It must be instantiated by the user with the type of
     53    *  character used in the file stream, e.g., stdio_filebuf<char>.
     54   */
     55   template<typename _CharT, typename _Traits = std::char_traits<_CharT> >
     56     class stdio_sync_filebuf : public std::basic_streambuf<_CharT, _Traits>
     57     {
     58     public:
     59       // Types:
     60       typedef _CharT					char_type;
     61       typedef _Traits					traits_type;
     62       typedef typename traits_type::int_type		int_type;
     63       typedef typename traits_type::pos_type		pos_type;
     64       typedef typename traits_type::off_type		off_type;
     65 
     66     private:
     67       // Underlying stdio FILE
     68       std::__c_file* const _M_file;
     69 
     70       // Last character gotten. This is used when pbackfail is
     71       // called from basic_streambuf::sungetc()
     72       int_type _M_unget_buf;
     73 
     74     public:
     75       explicit
     76       stdio_sync_filebuf(std::__c_file* __f)
     77       : _M_file(__f), _M_unget_buf(traits_type::eof())
     78       { }
     79 
     80       /**
     81        *  @return  The underlying FILE*.
     82        *
     83        *  This function can be used to access the underlying C file pointer.
     84        *  Note that there is no way for the library to track what you do
     85        *  with the file, so be careful.
     86        */
     87       std::__c_file* const
     88       file() { return this->_M_file; }
     89 
     90     protected:
     91       int_type
     92       syncgetc();
     93 
     94       int_type
     95       syncungetc(int_type __c);
     96 
     97       int_type
     98       syncputc(int_type __c);
     99 
    100       virtual int_type
    101       underflow()
    102       {
    103 	int_type __c = this->syncgetc();
    104 	return this->syncungetc(__c);
    105       }
    106 
    107       virtual int_type
    108       uflow()
    109       {
    110 	// Store the gotten character in case we need to unget it.
    111 	_M_unget_buf = this->syncgetc();
    112 	return _M_unget_buf;
    113       }
    114 
    115       virtual int_type
    116       pbackfail(int_type __c = traits_type::eof())
    117       {
    118 	int_type __ret;
    119 	const int_type __eof = traits_type::eof();
    120 
    121 	// Check if the unget or putback was requested
    122 	if (traits_type::eq_int_type(__c, __eof)) // unget
    123 	  {
    124 	    if (!traits_type::eq_int_type(_M_unget_buf, __eof))
    125 	      __ret = this->syncungetc(_M_unget_buf);
    126 	    else // buffer invalid, fail.
    127 	      __ret = __eof;
    128 	  }
    129 	else // putback
    130 	  __ret = this->syncungetc(__c);
    131 
    132 	// The buffered character is no longer valid, discard it.
    133 	_M_unget_buf = __eof;
    134 	return __ret;
    135       }
    136 
    137       virtual std::streamsize
    138       xsgetn(char_type* __s, std::streamsize __n);
    139 
    140       virtual int_type
    141       overflow(int_type __c = traits_type::eof())
    142       {
    143 	int_type __ret;
    144 	if (traits_type::eq_int_type(__c, traits_type::eof()))
    145 	  {
    146 	    if (std::fflush(_M_file))
    147 	      __ret = traits_type::eof();
    148 	    else
    149 	      __ret = traits_type::not_eof(__c);
    150 	  }
    151 	else
    152 	  __ret = this->syncputc(__c);
    153 	return __ret;
    154       }
    155 
    156       virtual std::streamsize
    157       xsputn(const char_type* __s, std::streamsize __n);
    158 
    159       virtual int
    160       sync()
    161       { return std::fflush(_M_file); }
    162 
    163       virtual std::streampos
    164       seekoff(std::streamoff __off, std::ios_base::seekdir __dir,
    165 	      std::ios_base::openmode = std::ios_base::in | std::ios_base::out)
    166       {
    167 	std::streampos __ret(std::streamoff(-1));
    168 	int __whence;
    169 	if (__dir == std::ios_base::beg)
    170 	  __whence = SEEK_SET;
    171 	else if (__dir == std::ios_base::cur)
    172 	  __whence = SEEK_CUR;
    173 	else
    174 	  __whence = SEEK_END;
    175 #ifdef _GLIBCXX_USE_LFS
    176 	if (!fseeko64(_M_file, __off, __whence))
    177 	  __ret = std::streampos(ftello64(_M_file));
    178 #else
    179 	if (!fseek(_M_file, __off, __whence))
    180 	  __ret = std::streampos(std::ftell(_M_file));
    181 #endif
    182 	return __ret;
    183       }
    184 
    185       virtual std::streampos
    186       seekpos(std::streampos __pos,
    187 	      std::ios_base::openmode __mode =
    188 	      std::ios_base::in | std::ios_base::out)
    189       { return seekoff(std::streamoff(__pos), std::ios_base::beg, __mode); }
    190     };
    191 
    192   template<>
    193     inline stdio_sync_filebuf<char>::int_type
    194     stdio_sync_filebuf<char>::syncgetc()
    195     { return std::getc(_M_file); }
    196 
    197   template<>
    198     inline stdio_sync_filebuf<char>::int_type
    199     stdio_sync_filebuf<char>::syncungetc(int_type __c)
    200     { return std::ungetc(__c, _M_file); }
    201 
    202   template<>
    203     inline stdio_sync_filebuf<char>::int_type
    204     stdio_sync_filebuf<char>::syncputc(int_type __c)
    205     { return std::putc(__c, _M_file); }
    206 
    207   template<>
    208     inline std::streamsize
    209     stdio_sync_filebuf<char>::xsgetn(char* __s, std::streamsize __n)
    210     {
    211       std::streamsize __ret = std::fread(__s, 1, __n, _M_file);
    212       if (__ret > 0)
    213 	_M_unget_buf = traits_type::to_int_type(__s[__ret - 1]);
    214       else
    215 	_M_unget_buf = traits_type::eof();
    216       return __ret;
    217     }
    218 
    219   template<>
    220     inline std::streamsize
    221     stdio_sync_filebuf<char>::xsputn(const char* __s, std::streamsize __n)
    222     { return std::fwrite(__s, 1, __n, _M_file); }
    223 
    224 #ifdef _GLIBCXX_USE_WCHAR_T
    225   template<>
    226     inline stdio_sync_filebuf<wchar_t>::int_type
    227     stdio_sync_filebuf<wchar_t>::syncgetc()
    228     { return std::getwc(_M_file); }
    229 
    230   template<>
    231     inline stdio_sync_filebuf<wchar_t>::int_type
    232     stdio_sync_filebuf<wchar_t>::syncungetc(int_type __c)
    233     { return std::ungetwc(__c, _M_file); }
    234 
    235   template<>
    236     inline stdio_sync_filebuf<wchar_t>::int_type
    237     stdio_sync_filebuf<wchar_t>::syncputc(int_type __c)
    238     { return std::putwc(__c, _M_file); }
    239 
    240   template<>
    241     inline std::streamsize
    242     stdio_sync_filebuf<wchar_t>::xsgetn(wchar_t* __s, std::streamsize __n)
    243     {
    244       std::streamsize __ret = 0;
    245       const int_type __eof = traits_type::eof();
    246       while (__n--)
    247 	{
    248 	  int_type __c = this->syncgetc();
    249 	  if (traits_type::eq_int_type(__c, __eof))
    250 	    break;
    251 	  __s[__ret] = traits_type::to_char_type(__c);
    252 	  ++__ret;
    253 	}
    254 
    255       if (__ret > 0)
    256 	_M_unget_buf = traits_type::to_int_type(__s[__ret - 1]);
    257       else
    258 	_M_unget_buf = traits_type::eof();
    259       return __ret;
    260     }
    261 
    262   template<>
    263     inline std::streamsize
    264     stdio_sync_filebuf<wchar_t>::xsputn(const wchar_t* __s,
    265 					std::streamsize __n)
    266     {
    267       std::streamsize __ret = 0;
    268       const int_type __eof = traits_type::eof();
    269       while (__n--)
    270 	{
    271 	  if (traits_type::eq_int_type(this->syncputc(*__s++), __eof))
    272 	    break;
    273 	  ++__ret;
    274 	}
    275       return __ret;
    276     }
    277 #endif
    278 
    279 #if _GLIBCXX_EXTERN_TEMPLATE
    280   extern template class stdio_sync_filebuf<char>;
    281 #ifdef _GLIBCXX_USE_WCHAR_T
    282   extern template class stdio_sync_filebuf<wchar_t>;
    283 #endif
    284 #endif
    285 
    286 _GLIBCXX_END_NAMESPACE_VERSION
    287 } // namespace
    288 
    289 #endif
    290