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