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