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