stdio_sync_filebuf.h 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. // Iostreams wrapper for stdio FILE* -*- C++ -*-
  2. // Copyright (C) 2003-2021 Free Software Foundation, Inc.
  3. //
  4. // This file is part of the GNU ISO C++ Library. This library is free
  5. // software; you can redistribute it and/or modify it under the
  6. // terms of the GNU General Public License as published by the
  7. // Free Software Foundation; either version 3, or (at your option)
  8. // any later version.
  9. // This library is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. // Under Section 7 of GPL version 3, you are granted additional
  14. // permissions described in the GCC Runtime Library Exception, version
  15. // 3.1, as published by the Free Software Foundation.
  16. // You should have received a copy of the GNU General Public License and
  17. // a copy of the GCC Runtime Library Exception along with this program;
  18. // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
  19. // <http://www.gnu.org/licenses/>.
  20. /** @file ext/stdio_sync_filebuf.h
  21. * This file is a GNU extension to the Standard C++ Library.
  22. */
  23. #ifndef _STDIO_SYNC_FILEBUF_H
  24. #define _STDIO_SYNC_FILEBUF_H 1
  25. #pragma GCC system_header
  26. #include <streambuf>
  27. #include <cstdio>
  28. #include <bits/c++io.h> // For __c_file
  29. #include <bits/move.h> // For __exchange
  30. #ifdef _GLIBCXX_USE_WCHAR_T
  31. #include <cwchar>
  32. #endif
  33. namespace __gnu_cxx _GLIBCXX_VISIBILITY(default)
  34. {
  35. _GLIBCXX_BEGIN_NAMESPACE_VERSION
  36. /**
  37. * @brief Provides a layer of compatibility for C.
  38. * @ingroup io
  39. *
  40. * This GNU extension provides extensions for working with standard
  41. * C FILE*'s. It must be instantiated by the user with the type of
  42. * character used in the file stream, e.g., stdio_filebuf<char>.
  43. */
  44. template<typename _CharT, typename _Traits = std::char_traits<_CharT> >
  45. class stdio_sync_filebuf : public std::basic_streambuf<_CharT, _Traits>
  46. {
  47. public:
  48. // Types:
  49. typedef _CharT char_type;
  50. typedef _Traits traits_type;
  51. typedef typename traits_type::int_type int_type;
  52. typedef typename traits_type::pos_type pos_type;
  53. typedef typename traits_type::off_type off_type;
  54. private:
  55. typedef std::basic_streambuf<_CharT, _Traits> __streambuf_type;
  56. // Underlying stdio FILE
  57. std::__c_file* _M_file;
  58. // Last character gotten. This is used when pbackfail is
  59. // called from basic_streambuf::sungetc()
  60. int_type _M_unget_buf;
  61. public:
  62. explicit
  63. stdio_sync_filebuf(std::__c_file* __f)
  64. : _M_file(__f), _M_unget_buf(traits_type::eof())
  65. { }
  66. #if __cplusplus >= 201103L
  67. stdio_sync_filebuf(stdio_sync_filebuf&& __fb) noexcept
  68. : __streambuf_type(std::move(__fb)),
  69. _M_file(__fb._M_file), _M_unget_buf(__fb._M_unget_buf)
  70. {
  71. __fb._M_file = nullptr;
  72. __fb._M_unget_buf = traits_type::eof();
  73. }
  74. stdio_sync_filebuf&
  75. operator=(stdio_sync_filebuf&& __fb) noexcept
  76. {
  77. __streambuf_type::operator=(__fb);
  78. _M_file = std::__exchange(__fb._M_file, nullptr);
  79. _M_unget_buf = std::__exchange(__fb._M_unget_buf, traits_type::eof());
  80. return *this;
  81. }
  82. void
  83. swap(stdio_sync_filebuf& __fb)
  84. {
  85. __streambuf_type::swap(__fb);
  86. std::swap(_M_file, __fb._M_file);
  87. std::swap(_M_unget_buf, __fb._M_unget_buf);
  88. }
  89. #endif
  90. /**
  91. * @return The underlying FILE*.
  92. *
  93. * This function can be used to access the underlying C file pointer.
  94. * Note that there is no way for the library to track what you do
  95. * with the file, so be careful.
  96. */
  97. std::__c_file*
  98. file() { return this->_M_file; }
  99. protected:
  100. int_type
  101. syncgetc();
  102. int_type
  103. syncungetc(int_type __c);
  104. int_type
  105. syncputc(int_type __c);
  106. virtual int_type
  107. underflow()
  108. {
  109. int_type __c = this->syncgetc();
  110. return this->syncungetc(__c);
  111. }
  112. virtual int_type
  113. uflow()
  114. {
  115. // Store the gotten character in case we need to unget it.
  116. _M_unget_buf = this->syncgetc();
  117. return _M_unget_buf;
  118. }
  119. virtual int_type
  120. pbackfail(int_type __c = traits_type::eof())
  121. {
  122. int_type __ret;
  123. const int_type __eof = traits_type::eof();
  124. // Check if the unget or putback was requested
  125. if (traits_type::eq_int_type(__c, __eof)) // unget
  126. {
  127. if (!traits_type::eq_int_type(_M_unget_buf, __eof))
  128. __ret = this->syncungetc(_M_unget_buf);
  129. else // buffer invalid, fail.
  130. __ret = __eof;
  131. }
  132. else // putback
  133. __ret = this->syncungetc(__c);
  134. // The buffered character is no longer valid, discard it.
  135. _M_unget_buf = __eof;
  136. return __ret;
  137. }
  138. virtual std::streamsize
  139. xsgetn(char_type* __s, std::streamsize __n);
  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. virtual std::streamsize
  156. xsputn(const char_type* __s, std::streamsize __n);
  157. virtual int
  158. sync()
  159. { return std::fflush(_M_file); }
  160. virtual std::streampos
  161. seekoff(std::streamoff __off, std::ios_base::seekdir __dir,
  162. std::ios_base::openmode = std::ios_base::in | std::ios_base::out)
  163. {
  164. std::streampos __ret(std::streamoff(-1));
  165. int __whence;
  166. if (__dir == std::ios_base::beg)
  167. __whence = SEEK_SET;
  168. else if (__dir == std::ios_base::cur)
  169. __whence = SEEK_CUR;
  170. else
  171. __whence = SEEK_END;
  172. #ifdef _GLIBCXX_USE_LFS
  173. if (!fseeko64(_M_file, __off, __whence))
  174. __ret = std::streampos(ftello64(_M_file));
  175. #else
  176. if (!fseek(_M_file, __off, __whence))
  177. __ret = std::streampos(std::ftell(_M_file));
  178. #endif
  179. return __ret;
  180. }
  181. virtual std::streampos
  182. seekpos(std::streampos __pos,
  183. std::ios_base::openmode __mode =
  184. std::ios_base::in | std::ios_base::out)
  185. { return seekoff(std::streamoff(__pos), std::ios_base::beg, __mode); }
  186. };
  187. template<>
  188. inline stdio_sync_filebuf<char>::int_type
  189. stdio_sync_filebuf<char>::syncgetc()
  190. { return std::getc(_M_file); }
  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. template<>
  196. inline stdio_sync_filebuf<char>::int_type
  197. stdio_sync_filebuf<char>::syncputc(int_type __c)
  198. { return std::putc(__c, _M_file); }
  199. template<>
  200. inline std::streamsize
  201. stdio_sync_filebuf<char>::xsgetn(char* __s, std::streamsize __n)
  202. {
  203. std::streamsize __ret = std::fread(__s, 1, __n, _M_file);
  204. if (__ret > 0)
  205. _M_unget_buf = traits_type::to_int_type(__s[__ret - 1]);
  206. else
  207. _M_unget_buf = traits_type::eof();
  208. return __ret;
  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. #ifdef _GLIBCXX_USE_WCHAR_T
  215. template<>
  216. inline stdio_sync_filebuf<wchar_t>::int_type
  217. stdio_sync_filebuf<wchar_t>::syncgetc()
  218. { return std::getwc(_M_file); }
  219. template<>
  220. inline stdio_sync_filebuf<wchar_t>::int_type
  221. stdio_sync_filebuf<wchar_t>::syncungetc(int_type __c)
  222. { return std::ungetwc(__c, _M_file); }
  223. template<>
  224. inline stdio_sync_filebuf<wchar_t>::int_type
  225. stdio_sync_filebuf<wchar_t>::syncputc(int_type __c)
  226. { return std::putwc(__c, _M_file); }
  227. template<>
  228. inline std::streamsize
  229. stdio_sync_filebuf<wchar_t>::xsgetn(wchar_t* __s, std::streamsize __n)
  230. {
  231. std::streamsize __ret = 0;
  232. const int_type __eof = traits_type::eof();
  233. while (__n--)
  234. {
  235. int_type __c = this->syncgetc();
  236. if (traits_type::eq_int_type(__c, __eof))
  237. break;
  238. __s[__ret] = traits_type::to_char_type(__c);
  239. ++__ret;
  240. }
  241. if (__ret > 0)
  242. _M_unget_buf = traits_type::to_int_type(__s[__ret - 1]);
  243. else
  244. _M_unget_buf = traits_type::eof();
  245. return __ret;
  246. }
  247. template<>
  248. inline std::streamsize
  249. stdio_sync_filebuf<wchar_t>::xsputn(const wchar_t* __s,
  250. std::streamsize __n)
  251. {
  252. std::streamsize __ret = 0;
  253. const int_type __eof = traits_type::eof();
  254. while (__n--)
  255. {
  256. if (traits_type::eq_int_type(this->syncputc(*__s++), __eof))
  257. break;
  258. ++__ret;
  259. }
  260. return __ret;
  261. }
  262. #endif
  263. #if _GLIBCXX_EXTERN_TEMPLATE
  264. extern template class stdio_sync_filebuf<char>;
  265. #ifdef _GLIBCXX_USE_WCHAR_T
  266. extern template class stdio_sync_filebuf<wchar_t>;
  267. #endif
  268. #endif
  269. _GLIBCXX_END_NAMESPACE_VERSION
  270. } // namespace
  271. #endif