1// Iostreams wrapper for stdio FILE* -*- C++ -*- 2 3// Copyright (C) 2003, 2004, 2005 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 2, 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// You should have received a copy of the GNU General Public License along 17// with this library; see the file COPYING. If not, write to the Free 18// Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 19// USA. 20 21// As a special exception, you may use this file as part of a free software 22// library without restriction. Specifically, if other files instantiate 23// templates or use macros or inline functions from this file, or you compile 24// this file and link it with other files to produce an executable, this 25// file does not by itself cause the resulting executable to be covered by 26// the GNU General Public License. This exception does not however 27// invalidate any other reasons why the executable file might be covered by 28// the GNU General Public License. 29 30/** @file ext/stdio_sync_filebuf.h 31 * This file is a GNU extension to the Standard C++ Library. 32 */ 33 34#ifndef _STDIO_SYNC_FILEBUF_H 35#define _STDIO_SYNC_FILEBUF_H 1 36 37#pragma GCC system_header 38 39#include <streambuf> 40#include <unistd.h> 41#include <cstdio> 42 43#ifdef _GLIBCXX_USE_WCHAR_T 44#include <cwchar> 45#endif 46 47_GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx) 48 49 /// @brief class stdio_sync_filebuf. 50 template<typename _CharT, typename _Traits = std::char_traits<_CharT> > 51 class stdio_sync_filebuf : public std::basic_streambuf<_CharT, _Traits> 52 { 53 public: 54 // Types: 55 typedef _CharT char_type; 56 typedef _Traits traits_type; 57 typedef typename traits_type::int_type int_type; 58 typedef typename traits_type::pos_type pos_type; 59 typedef typename traits_type::off_type off_type; 60 61 private: 62 // Underlying stdio FILE 63 std::__c_file* const _M_file; 64 65 // Last character gotten. This is used when pbackfail is 66 // called from basic_streambuf::sungetc() 67 int_type _M_unget_buf; 68 69 public: 70 explicit 71 stdio_sync_filebuf(std::__c_file* __f) 72 : _M_file(__f), _M_unget_buf(traits_type::eof()) 73 { } 74 75 /** 76 * @return The underlying FILE*. 77 * 78 * This function can be used to access the underlying "C" file pointer. 79 * Note that there is no way for the library to track what you do 80 * with the file, so be careful. 81 */ 82 std::__c_file* const 83 file() { return this->_M_file; } 84 85 protected: 86 int_type 87 syncgetc(); 88 89 int_type 90 syncungetc(int_type __c); 91 92 int_type 93 syncputc(int_type __c); 94 95 virtual int_type 96 underflow() 97 { 98 int_type __c = this->syncgetc(); 99 return this->syncungetc(__c); 100 } 101 102 virtual int_type 103 uflow() 104 { 105 // Store the gotten character in case we need to unget it. 106 _M_unget_buf = this->syncgetc(); 107 return _M_unget_buf; 108 } 109 110 virtual int_type 111 pbackfail(int_type __c = traits_type::eof()) 112 { 113 int_type __ret; 114 const int_type __eof = traits_type::eof(); 115 116 // Check if the unget or putback was requested 117 if (traits_type::eq_int_type(__c, __eof)) // unget 118 { 119 if (!traits_type::eq_int_type(_M_unget_buf, __eof)) 120 __ret = this->syncungetc(_M_unget_buf); 121 else // buffer invalid, fail. 122 __ret = __eof; 123 } 124 else // putback 125 __ret = this->syncungetc(__c); 126 127 // The buffered character is no longer valid, discard it. 128 _M_unget_buf = __eof; 129 return __ret; 130 } 131 132 virtual std::streamsize 133 xsgetn(char_type* __s, std::streamsize __n); 134 135 virtual int_type 136 overflow(int_type __c = traits_type::eof()) 137 { 138 int_type __ret; 139 if (traits_type::eq_int_type(__c, traits_type::eof())) 140 { 141 if (std::fflush(_M_file)) 142 __ret = traits_type::eof(); 143 else 144 __ret = traits_type::not_eof(__c); 145 } 146 else 147 __ret = this->syncputc(__c); 148 return __ret; 149 } 150 151 virtual std::streamsize 152 xsputn(const char_type* __s, std::streamsize __n); 153 154 virtual int 155 sync() 156 { return std::fflush(_M_file); } 157 158 virtual std::streampos 159 seekoff(std::streamoff __off, std::ios_base::seekdir __dir, 160 std::ios_base::openmode = std::ios_base::in | std::ios_base::out) 161 { 162 std::streampos __ret(std::streamoff(-1)); 163 int __whence; 164 if (__dir == std::ios_base::beg) 165 __whence = SEEK_SET; 166 else if (__dir == std::ios_base::cur) 167 __whence = SEEK_CUR; 168 else 169 __whence = SEEK_END; 170#ifdef _GLIBCXX_USE_LFS 171 if (!fseeko64(_M_file, __off, __whence)) 172 __ret = std::streampos(ftello64(_M_file)); 173#else 174 if (!fseek(_M_file, __off, __whence)) 175 __ret = std::streampos(std::ftell(_M_file)); 176#endif 177 return __ret; 178 } 179 180 virtual std::streampos 181 seekpos(std::streampos __pos, 182 std::ios_base::openmode __mode = 183 std::ios_base::in | std::ios_base::out) 184 { return seekoff(std::streamoff(__pos), std::ios_base::beg, __mode); } 185 }; 186 187 template<> 188 inline stdio_sync_filebuf<char>::int_type 189 stdio_sync_filebuf<char>::syncgetc() 190 { return std::getc(_M_file); } 191 192 template<> 193 inline stdio_sync_filebuf<char>::int_type 194 stdio_sync_filebuf<char>::syncungetc(int_type __c) 195 { return std::ungetc(__c, _M_file); } 196 197 template<> 198 inline stdio_sync_filebuf<char>::int_type 199 stdio_sync_filebuf<char>::syncputc(int_type __c) 200 { return std::putc(__c, _M_file); } 201 202 template<> 203 inline std::streamsize 204 stdio_sync_filebuf<char>::xsgetn(char* __s, std::streamsize __n) 205 { 206 std::streamsize __ret = std::fread(__s, 1, __n, _M_file); 207 if (__ret > 0) 208 _M_unget_buf = traits_type::to_int_type(__s[__ret - 1]); 209 else 210 _M_unget_buf = traits_type::eof(); 211 return __ret; 212 } 213 214 template<> 215 inline std::streamsize 216 stdio_sync_filebuf<char>::xsputn(const char* __s, std::streamsize __n) 217 { return std::fwrite(__s, 1, __n, _M_file); } 218 219#ifdef _GLIBCXX_USE_WCHAR_T 220 template<> 221 inline stdio_sync_filebuf<wchar_t>::int_type 222 stdio_sync_filebuf<wchar_t>::syncgetc() 223 { return std::getwc(_M_file); } 224 225 template<> 226 inline stdio_sync_filebuf<wchar_t>::int_type 227 stdio_sync_filebuf<wchar_t>::syncungetc(int_type __c) 228 { return std::ungetwc(__c, _M_file); } 229 230 template<> 231 inline stdio_sync_filebuf<wchar_t>::int_type 232 stdio_sync_filebuf<wchar_t>::syncputc(int_type __c) 233 { return std::putwc(__c, _M_file); } 234 235 template<> 236 inline std::streamsize 237 stdio_sync_filebuf<wchar_t>::xsgetn(wchar_t* __s, std::streamsize __n) 238 { 239 std::streamsize __ret = 0; 240 const int_type __eof = traits_type::eof(); 241 while (__n--) 242 { 243 int_type __c = this->syncgetc(); 244 if (traits_type::eq_int_type(__c, __eof)) 245 break; 246 __s[__ret] = traits_type::to_char_type(__c); 247 ++__ret; 248 } 249 250 if (__ret > 0) 251 _M_unget_buf = traits_type::to_int_type(__s[__ret - 1]); 252 else 253 _M_unget_buf = traits_type::eof(); 254 return __ret; 255 } 256 257 template<> 258 inline std::streamsize 259 stdio_sync_filebuf<wchar_t>::xsputn(const wchar_t* __s, 260 std::streamsize __n) 261 { 262 std::streamsize __ret = 0; 263 const int_type __eof = traits_type::eof(); 264 while (__n--) 265 { 266 if (traits_type::eq_int_type(this->syncputc(*__s++), __eof)) 267 break; 268 ++__ret; 269 } 270 return __ret; 271 } 272#endif 273 274#if _GLIBCXX_EXTERN_TEMPLATE 275 extern template class stdio_sync_filebuf<char>; 276#ifdef _GLIBCXX_USE_WCHAR_T 277 extern template class stdio_sync_filebuf<wchar_t>; 278#endif 279#endif 280 281_GLIBCXX_END_NAMESPACE 282 283#endif 284