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