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