1132720Skan// Iostreams wrapper for stdio FILE* -*- C++ -*- 2132720Skan 3169691Skan// Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. 4132720Skan// 5132720Skan// This file is part of the GNU ISO C++ Library. This library is free 6132720Skan// software; you can redistribute it and/or modify it under the 7132720Skan// terms of the GNU General Public License as published by the 8132720Skan// Free Software Foundation; either version 2, or (at your option) 9132720Skan// any later version. 10132720Skan 11132720Skan// This library is distributed in the hope that it will be useful, 12132720Skan// but WITHOUT ANY WARRANTY; without even the implied warranty of 13132720Skan// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14132720Skan// GNU General Public License for more details. 15132720Skan 16132720Skan// You should have received a copy of the GNU General Public License along 17132720Skan// with this library; see the file COPYING. If not, write to the Free 18169691Skan// Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 19132720Skan// USA. 20132720Skan 21132720Skan// As a special exception, you may use this file as part of a free software 22132720Skan// library without restriction. Specifically, if other files instantiate 23132720Skan// templates or use macros or inline functions from this file, or you compile 24132720Skan// this file and link it with other files to produce an executable, this 25132720Skan// file does not by itself cause the resulting executable to be covered by 26132720Skan// the GNU General Public License. This exception does not however 27132720Skan// invalidate any other reasons why the executable file might be covered by 28132720Skan// the GNU General Public License. 29132720Skan 30169691Skan/** @file ext/stdio_sync_filebuf.h 31132720Skan * This file is a GNU extension to the Standard C++ Library. 32132720Skan */ 33132720Skan 34132720Skan#ifndef _STDIO_SYNC_FILEBUF_H 35132720Skan#define _STDIO_SYNC_FILEBUF_H 1 36132720Skan 37132720Skan#pragma GCC system_header 38132720Skan 39132720Skan#include <streambuf> 40132720Skan#include <unistd.h> 41132720Skan#include <cstdio> 42132720Skan 43132720Skan#ifdef _GLIBCXX_USE_WCHAR_T 44132720Skan#include <cwchar> 45132720Skan#endif 46132720Skan 47169691Skan_GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx) 48169691Skan 49169691Skan /// @brief class stdio_sync_filebuf. 50132720Skan template<typename _CharT, typename _Traits = std::char_traits<_CharT> > 51132720Skan class stdio_sync_filebuf : public std::basic_streambuf<_CharT, _Traits> 52132720Skan { 53132720Skan public: 54132720Skan // Types: 55132720Skan typedef _CharT char_type; 56132720Skan typedef _Traits traits_type; 57132720Skan typedef typename traits_type::int_type int_type; 58132720Skan typedef typename traits_type::pos_type pos_type; 59132720Skan typedef typename traits_type::off_type off_type; 60132720Skan 61132720Skan private: 62132720Skan // Underlying stdio FILE 63132720Skan std::__c_file* const _M_file; 64132720Skan 65132720Skan // Last character gotten. This is used when pbackfail is 66132720Skan // called from basic_streambuf::sungetc() 67132720Skan int_type _M_unget_buf; 68132720Skan 69132720Skan public: 70132720Skan explicit 71132720Skan stdio_sync_filebuf(std::__c_file* __f) 72132720Skan : _M_file(__f), _M_unget_buf(traits_type::eof()) 73132720Skan { } 74132720Skan 75132720Skan /** 76132720Skan * @return The underlying FILE*. 77132720Skan * 78132720Skan * This function can be used to access the underlying "C" file pointer. 79132720Skan * Note that there is no way for the library to track what you do 80132720Skan * with the file, so be careful. 81132720Skan */ 82132720Skan std::__c_file* const 83132720Skan file() { return this->_M_file; } 84132720Skan 85132720Skan protected: 86132720Skan int_type 87132720Skan syncgetc(); 88132720Skan 89132720Skan int_type 90132720Skan syncungetc(int_type __c); 91132720Skan 92132720Skan int_type 93132720Skan syncputc(int_type __c); 94132720Skan 95132720Skan virtual int_type 96132720Skan underflow() 97132720Skan { 98132720Skan int_type __c = this->syncgetc(); 99132720Skan return this->syncungetc(__c); 100132720Skan } 101132720Skan 102132720Skan virtual int_type 103132720Skan uflow() 104132720Skan { 105132720Skan // Store the gotten character in case we need to unget it. 106132720Skan _M_unget_buf = this->syncgetc(); 107132720Skan return _M_unget_buf; 108132720Skan } 109132720Skan 110132720Skan virtual int_type 111132720Skan pbackfail(int_type __c = traits_type::eof()) 112132720Skan { 113132720Skan int_type __ret; 114132720Skan const int_type __eof = traits_type::eof(); 115132720Skan 116132720Skan // Check if the unget or putback was requested 117132720Skan if (traits_type::eq_int_type(__c, __eof)) // unget 118132720Skan { 119132720Skan if (!traits_type::eq_int_type(_M_unget_buf, __eof)) 120132720Skan __ret = this->syncungetc(_M_unget_buf); 121132720Skan else // buffer invalid, fail. 122132720Skan __ret = __eof; 123132720Skan } 124132720Skan else // putback 125132720Skan __ret = this->syncungetc(__c); 126132720Skan 127132720Skan // The buffered character is no longer valid, discard it. 128132720Skan _M_unget_buf = __eof; 129132720Skan return __ret; 130132720Skan } 131132720Skan 132132720Skan virtual std::streamsize 133132720Skan xsgetn(char_type* __s, std::streamsize __n); 134132720Skan 135132720Skan virtual int_type 136132720Skan overflow(int_type __c = traits_type::eof()) 137132720Skan { 138132720Skan int_type __ret; 139132720Skan if (traits_type::eq_int_type(__c, traits_type::eof())) 140132720Skan { 141132720Skan if (std::fflush(_M_file)) 142132720Skan __ret = traits_type::eof(); 143132720Skan else 144132720Skan __ret = traits_type::not_eof(__c); 145132720Skan } 146132720Skan else 147132720Skan __ret = this->syncputc(__c); 148132720Skan return __ret; 149132720Skan } 150132720Skan 151132720Skan virtual std::streamsize 152132720Skan xsputn(const char_type* __s, std::streamsize __n); 153132720Skan 154132720Skan virtual int 155132720Skan sync() 156132720Skan { return std::fflush(_M_file); } 157132720Skan 158132720Skan virtual std::streampos 159132720Skan seekoff(std::streamoff __off, std::ios_base::seekdir __dir, 160132720Skan std::ios_base::openmode = std::ios_base::in | std::ios_base::out) 161132720Skan { 162132720Skan std::streampos __ret(std::streamoff(-1)); 163132720Skan int __whence; 164132720Skan if (__dir == std::ios_base::beg) 165132720Skan __whence = SEEK_SET; 166132720Skan else if (__dir == std::ios_base::cur) 167132720Skan __whence = SEEK_CUR; 168132720Skan else 169132720Skan __whence = SEEK_END; 170132720Skan#ifdef _GLIBCXX_USE_LFS 171132720Skan if (!fseeko64(_M_file, __off, __whence)) 172132720Skan __ret = std::streampos(ftello64(_M_file)); 173132720Skan#else 174132720Skan if (!fseek(_M_file, __off, __whence)) 175132720Skan __ret = std::streampos(std::ftell(_M_file)); 176132720Skan#endif 177132720Skan return __ret; 178132720Skan } 179132720Skan 180132720Skan virtual std::streampos 181132720Skan seekpos(std::streampos __pos, 182132720Skan std::ios_base::openmode __mode = 183132720Skan std::ios_base::in | std::ios_base::out) 184132720Skan { return seekoff(std::streamoff(__pos), std::ios_base::beg, __mode); } 185132720Skan }; 186132720Skan 187132720Skan template<> 188132720Skan inline stdio_sync_filebuf<char>::int_type 189132720Skan stdio_sync_filebuf<char>::syncgetc() 190132720Skan { return std::getc(_M_file); } 191132720Skan 192132720Skan template<> 193132720Skan inline stdio_sync_filebuf<char>::int_type 194132720Skan stdio_sync_filebuf<char>::syncungetc(int_type __c) 195132720Skan { return std::ungetc(__c, _M_file); } 196132720Skan 197132720Skan template<> 198132720Skan inline stdio_sync_filebuf<char>::int_type 199132720Skan stdio_sync_filebuf<char>::syncputc(int_type __c) 200132720Skan { return std::putc(__c, _M_file); } 201132720Skan 202132720Skan template<> 203132720Skan inline std::streamsize 204132720Skan stdio_sync_filebuf<char>::xsgetn(char* __s, std::streamsize __n) 205132720Skan { 206132720Skan std::streamsize __ret = std::fread(__s, 1, __n, _M_file); 207132720Skan if (__ret > 0) 208132720Skan _M_unget_buf = traits_type::to_int_type(__s[__ret - 1]); 209132720Skan else 210132720Skan _M_unget_buf = traits_type::eof(); 211132720Skan return __ret; 212132720Skan } 213132720Skan 214132720Skan template<> 215132720Skan inline std::streamsize 216132720Skan stdio_sync_filebuf<char>::xsputn(const char* __s, std::streamsize __n) 217132720Skan { return std::fwrite(__s, 1, __n, _M_file); } 218132720Skan 219132720Skan#ifdef _GLIBCXX_USE_WCHAR_T 220132720Skan template<> 221132720Skan inline stdio_sync_filebuf<wchar_t>::int_type 222132720Skan stdio_sync_filebuf<wchar_t>::syncgetc() 223132720Skan { return std::getwc(_M_file); } 224132720Skan 225132720Skan template<> 226132720Skan inline stdio_sync_filebuf<wchar_t>::int_type 227132720Skan stdio_sync_filebuf<wchar_t>::syncungetc(int_type __c) 228132720Skan { return std::ungetwc(__c, _M_file); } 229132720Skan 230132720Skan template<> 231132720Skan inline stdio_sync_filebuf<wchar_t>::int_type 232132720Skan stdio_sync_filebuf<wchar_t>::syncputc(int_type __c) 233132720Skan { return std::putwc(__c, _M_file); } 234132720Skan 235132720Skan template<> 236132720Skan inline std::streamsize 237132720Skan stdio_sync_filebuf<wchar_t>::xsgetn(wchar_t* __s, std::streamsize __n) 238132720Skan { 239132720Skan std::streamsize __ret = 0; 240132720Skan const int_type __eof = traits_type::eof(); 241132720Skan while (__n--) 242132720Skan { 243132720Skan int_type __c = this->syncgetc(); 244132720Skan if (traits_type::eq_int_type(__c, __eof)) 245132720Skan break; 246132720Skan __s[__ret] = traits_type::to_char_type(__c); 247132720Skan ++__ret; 248132720Skan } 249132720Skan 250132720Skan if (__ret > 0) 251132720Skan _M_unget_buf = traits_type::to_int_type(__s[__ret - 1]); 252132720Skan else 253132720Skan _M_unget_buf = traits_type::eof(); 254132720Skan return __ret; 255132720Skan } 256132720Skan 257132720Skan template<> 258132720Skan inline std::streamsize 259132720Skan stdio_sync_filebuf<wchar_t>::xsputn(const wchar_t* __s, 260132720Skan std::streamsize __n) 261132720Skan { 262132720Skan std::streamsize __ret = 0; 263132720Skan const int_type __eof = traits_type::eof(); 264132720Skan while (__n--) 265132720Skan { 266132720Skan if (traits_type::eq_int_type(this->syncputc(*__s++), __eof)) 267132720Skan break; 268132720Skan ++__ret; 269132720Skan } 270132720Skan return __ret; 271132720Skan } 272132720Skan#endif 273132720Skan 274132720Skan#if _GLIBCXX_EXTERN_TEMPLATE 275132720Skan extern template class stdio_sync_filebuf<char>; 276132720Skan#ifdef _GLIBCXX_USE_WCHAR_T 277132720Skan extern template class stdio_sync_filebuf<wchar_t>; 278132720Skan#endif 279132720Skan#endif 280132720Skan 281169691Skan_GLIBCXX_END_NAMESPACE 282169691Skan 283132720Skan#endif 284