stdio_sync_filebuf.h 8.6 KB

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