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