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