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