You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1103 lines
33KB

  1. // File based streams -*- C++ -*-
  2. // Copyright (C) 1997-2020 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 bits/fstream.tcc
  21. * This is an internal header file, included by other library headers.
  22. * Do not attempt to use it directly. @headername{fstream}
  23. */
  24. //
  25. // ISO C++ 14882: 27.8 File-based streams
  26. //
  27. #ifndef _FSTREAM_TCC
  28. #define _FSTREAM_TCC 1
  29. #pragma GCC system_header
  30. #include <bits/cxxabi_forced.h>
  31. #include <bits/move.h> // for swap
  32. #include <cerrno>
  33. namespace std _GLIBCXX_VISIBILITY(default)
  34. {
  35. _GLIBCXX_BEGIN_NAMESPACE_VERSION
  36. template<typename _CharT, typename _Traits>
  37. void
  38. basic_filebuf<_CharT, _Traits>::
  39. _M_allocate_internal_buffer()
  40. {
  41. // Allocate internal buffer only if one doesn't already exist
  42. // (either allocated or provided by the user via setbuf).
  43. if (!_M_buf_allocated && !_M_buf)
  44. {
  45. _M_buf = new char_type[_M_buf_size];
  46. _M_buf_allocated = true;
  47. }
  48. }
  49. template<typename _CharT, typename _Traits>
  50. void
  51. basic_filebuf<_CharT, _Traits>::
  52. _M_destroy_internal_buffer() throw()
  53. {
  54. if (_M_buf_allocated)
  55. {
  56. delete [] _M_buf;
  57. _M_buf = 0;
  58. _M_buf_allocated = false;
  59. }
  60. delete [] _M_ext_buf;
  61. _M_ext_buf = 0;
  62. _M_ext_buf_size = 0;
  63. _M_ext_next = 0;
  64. _M_ext_end = 0;
  65. }
  66. template<typename _CharT, typename _Traits>
  67. basic_filebuf<_CharT, _Traits>::
  68. basic_filebuf() : __streambuf_type(), _M_lock(), _M_file(&_M_lock),
  69. _M_mode(ios_base::openmode(0)), _M_state_beg(), _M_state_cur(),
  70. _M_state_last(), _M_buf(0), _M_buf_size(BUFSIZ),
  71. _M_buf_allocated(false), _M_reading(false), _M_writing(false), _M_pback(),
  72. _M_pback_cur_save(0), _M_pback_end_save(0), _M_pback_init(false),
  73. _M_codecvt(0), _M_ext_buf(0), _M_ext_buf_size(0), _M_ext_next(0),
  74. _M_ext_end(0)
  75. {
  76. if (has_facet<__codecvt_type>(this->_M_buf_locale))
  77. _M_codecvt = &use_facet<__codecvt_type>(this->_M_buf_locale);
  78. }
  79. #if __cplusplus >= 201103L
  80. template<typename _CharT, typename _Traits>
  81. basic_filebuf<_CharT, _Traits>::
  82. basic_filebuf(basic_filebuf&& __rhs)
  83. : __streambuf_type(__rhs),
  84. _M_lock(), _M_file(std::move(__rhs._M_file), &_M_lock),
  85. _M_mode(std::__exchange(__rhs._M_mode, ios_base::openmode(0))),
  86. _M_state_beg(std::move(__rhs._M_state_beg)),
  87. _M_state_cur(std::move(__rhs._M_state_cur)),
  88. _M_state_last(std::move(__rhs._M_state_last)),
  89. _M_buf(std::__exchange(__rhs._M_buf, nullptr)),
  90. _M_buf_size(std::__exchange(__rhs._M_buf_size, 1)),
  91. _M_buf_allocated(std::__exchange(__rhs._M_buf_allocated, false)),
  92. _M_reading(std::__exchange(__rhs._M_reading, false)),
  93. _M_writing(std::__exchange(__rhs._M_writing, false)),
  94. _M_pback(__rhs._M_pback),
  95. _M_pback_cur_save(std::__exchange(__rhs._M_pback_cur_save, nullptr)),
  96. _M_pback_end_save(std::__exchange(__rhs._M_pback_end_save, nullptr)),
  97. _M_pback_init(std::__exchange(__rhs._M_pback_init, false)),
  98. _M_codecvt(__rhs._M_codecvt),
  99. _M_ext_buf(std::__exchange(__rhs._M_ext_buf, nullptr)),
  100. _M_ext_buf_size(std::__exchange(__rhs._M_ext_buf_size, 0)),
  101. _M_ext_next(std::__exchange(__rhs._M_ext_next, nullptr)),
  102. _M_ext_end(std::__exchange(__rhs._M_ext_end, nullptr))
  103. {
  104. __rhs._M_set_buffer(-1);
  105. __rhs._M_state_last = __rhs._M_state_cur = __rhs._M_state_beg;
  106. }
  107. template<typename _CharT, typename _Traits>
  108. basic_filebuf<_CharT, _Traits>&
  109. basic_filebuf<_CharT, _Traits>::
  110. operator=(basic_filebuf&& __rhs)
  111. {
  112. this->close();
  113. __streambuf_type::operator=(__rhs);
  114. _M_file.swap(__rhs._M_file);
  115. _M_mode = std::__exchange(__rhs._M_mode, ios_base::openmode(0));
  116. _M_state_beg = std::move(__rhs._M_state_beg);
  117. _M_state_cur = std::move(__rhs._M_state_cur);
  118. _M_state_last = std::move(__rhs._M_state_last);
  119. _M_buf = std::__exchange(__rhs._M_buf, nullptr);
  120. _M_buf_size = std::__exchange(__rhs._M_buf_size, 1);
  121. _M_buf_allocated = std::__exchange(__rhs._M_buf_allocated, false);
  122. _M_ext_buf = std::__exchange(__rhs._M_ext_buf, nullptr);
  123. _M_ext_buf_size = std::__exchange(__rhs._M_ext_buf_size, 0);
  124. _M_ext_next = std::__exchange(__rhs._M_ext_next, nullptr);
  125. _M_ext_end = std::__exchange(__rhs._M_ext_end, nullptr);
  126. _M_reading = std::__exchange(__rhs._M_reading, false);
  127. _M_writing = std::__exchange(__rhs._M_writing, false);
  128. _M_pback_cur_save = std::__exchange(__rhs._M_pback_cur_save, nullptr);
  129. _M_pback_end_save = std::__exchange(__rhs._M_pback_end_save, nullptr);
  130. _M_pback_init = std::__exchange(__rhs._M_pback_init, false);
  131. __rhs._M_set_buffer(-1);
  132. __rhs._M_state_last = __rhs._M_state_cur = __rhs._M_state_beg;
  133. return *this;
  134. }
  135. template<typename _CharT, typename _Traits>
  136. void
  137. basic_filebuf<_CharT, _Traits>::
  138. swap(basic_filebuf& __rhs)
  139. {
  140. __streambuf_type::swap(__rhs);
  141. _M_file.swap(__rhs._M_file);
  142. std::swap(_M_mode, __rhs._M_mode);
  143. std::swap(_M_state_beg, __rhs._M_state_beg);
  144. std::swap(_M_state_cur, __rhs._M_state_cur);
  145. std::swap(_M_state_last, __rhs._M_state_last);
  146. std::swap(_M_buf, __rhs._M_buf);
  147. std::swap(_M_buf_size, __rhs._M_buf_size);
  148. std::swap(_M_buf_allocated, __rhs._M_buf_allocated);
  149. std::swap(_M_ext_buf, __rhs._M_ext_buf);
  150. std::swap(_M_ext_buf_size, __rhs._M_ext_buf_size);
  151. std::swap(_M_ext_next, __rhs._M_ext_next);
  152. std::swap(_M_ext_end, __rhs._M_ext_end);
  153. std::swap(_M_reading, __rhs._M_reading);
  154. std::swap(_M_writing, __rhs._M_writing);
  155. std::swap(_M_pback_cur_save, __rhs._M_pback_cur_save);
  156. std::swap(_M_pback_end_save, __rhs._M_pback_end_save);
  157. std::swap(_M_pback_init, __rhs._M_pback_init);
  158. }
  159. #endif
  160. template<typename _CharT, typename _Traits>
  161. typename basic_filebuf<_CharT, _Traits>::__filebuf_type*
  162. basic_filebuf<_CharT, _Traits>::
  163. open(const char* __s, ios_base::openmode __mode)
  164. {
  165. __filebuf_type *__ret = 0;
  166. if (!this->is_open())
  167. {
  168. _M_file.open(__s, __mode);
  169. if (this->is_open())
  170. {
  171. _M_allocate_internal_buffer();
  172. _M_mode = __mode;
  173. // Setup initial buffer to 'uncommitted' mode.
  174. _M_reading = false;
  175. _M_writing = false;
  176. _M_set_buffer(-1);
  177. // Reset to initial state.
  178. _M_state_last = _M_state_cur = _M_state_beg;
  179. // 27.8.1.3,4
  180. if ((__mode & ios_base::ate)
  181. && this->seekoff(0, ios_base::end, __mode)
  182. == pos_type(off_type(-1)))
  183. this->close();
  184. else
  185. __ret = this;
  186. }
  187. }
  188. return __ret;
  189. }
  190. #if _GLIBCXX_HAVE__WFOPEN && _GLIBCXX_USE_WCHAR_T
  191. template<typename _CharT, typename _Traits>
  192. basic_filebuf<_CharT, _Traits>*
  193. basic_filebuf<_CharT, _Traits>::
  194. open(const wchar_t* __s, ios_base::openmode __mode)
  195. {
  196. __filebuf_type *__ret = 0;
  197. if (!this->is_open())
  198. {
  199. _M_file.open(__s, __mode);
  200. if (this->is_open())
  201. {
  202. _M_allocate_internal_buffer();
  203. _M_mode = __mode;
  204. // Setup initial buffer to 'uncommitted' mode.
  205. _M_reading = false;
  206. _M_writing = false;
  207. _M_set_buffer(-1);
  208. // Reset to initial state.
  209. _M_state_last = _M_state_cur = _M_state_beg;
  210. // 27.8.1.3,4
  211. if ((__mode & ios_base::ate)
  212. && this->seekoff(0, ios_base::end, __mode)
  213. == pos_type(off_type(-1)))
  214. this->close();
  215. else
  216. __ret = this;
  217. }
  218. }
  219. return __ret;
  220. }
  221. #endif // HAVE__WFOPEN && USE_WCHAR_T
  222. template<typename _CharT, typename _Traits>
  223. typename basic_filebuf<_CharT, _Traits>::__filebuf_type*
  224. basic_filebuf<_CharT, _Traits>::
  225. close()
  226. {
  227. if (!this->is_open())
  228. return 0;
  229. bool __testfail = false;
  230. {
  231. // NB: Do this here so that re-opened filebufs will be cool...
  232. struct __close_sentry
  233. {
  234. basic_filebuf *__fb;
  235. __close_sentry (basic_filebuf *__fbi): __fb(__fbi) { }
  236. ~__close_sentry ()
  237. {
  238. __fb->_M_mode = ios_base::openmode(0);
  239. __fb->_M_pback_init = false;
  240. __fb->_M_destroy_internal_buffer();
  241. __fb->_M_reading = false;
  242. __fb->_M_writing = false;
  243. __fb->_M_set_buffer(-1);
  244. __fb->_M_state_last = __fb->_M_state_cur = __fb->_M_state_beg;
  245. }
  246. } __cs (this);
  247. __try
  248. {
  249. if (!_M_terminate_output())
  250. __testfail = true;
  251. }
  252. __catch(...)
  253. {
  254. _M_file.close();
  255. __throw_exception_again;
  256. }
  257. }
  258. if (!_M_file.close())
  259. __testfail = true;
  260. if (__testfail)
  261. return 0;
  262. else
  263. return this;
  264. }
  265. template<typename _CharT, typename _Traits>
  266. streamsize
  267. basic_filebuf<_CharT, _Traits>::
  268. showmanyc()
  269. {
  270. streamsize __ret = -1;
  271. const bool __testin = _M_mode & ios_base::in;
  272. if (__testin && this->is_open())
  273. {
  274. // For a stateful encoding (-1) the pending sequence might be just
  275. // shift and unshift prefixes with no actual character.
  276. __ret = this->egptr() - this->gptr();
  277. #if _GLIBCXX_HAVE_DOS_BASED_FILESYSTEM
  278. // About this workaround, see libstdc++/20806.
  279. const bool __testbinary = _M_mode & ios_base::binary;
  280. if (__check_facet(_M_codecvt).encoding() >= 0
  281. && __testbinary)
  282. #else
  283. if (__check_facet(_M_codecvt).encoding() >= 0)
  284. #endif
  285. __ret += _M_file.showmanyc() / _M_codecvt->max_length();
  286. }
  287. return __ret;
  288. }
  289. template<typename _CharT, typename _Traits>
  290. typename basic_filebuf<_CharT, _Traits>::int_type
  291. basic_filebuf<_CharT, _Traits>::
  292. underflow()
  293. {
  294. int_type __ret = traits_type::eof();
  295. const bool __testin = _M_mode & ios_base::in;
  296. if (__testin)
  297. {
  298. if (_M_writing)
  299. {
  300. if (overflow() == traits_type::eof())
  301. return __ret;
  302. _M_set_buffer(-1);
  303. _M_writing = false;
  304. }
  305. // Check for pback madness, and if so switch back to the
  306. // normal buffers and jet outta here before expensive
  307. // fileops happen...
  308. _M_destroy_pback();
  309. if (this->gptr() < this->egptr())
  310. return traits_type::to_int_type(*this->gptr());
  311. // Get and convert input sequence.
  312. const size_t __buflen = _M_buf_size > 1 ? _M_buf_size - 1 : 1;
  313. // Will be set to true if ::read() returns 0 indicating EOF.
  314. bool __got_eof = false;
  315. // Number of internal characters produced.
  316. streamsize __ilen = 0;
  317. codecvt_base::result __r = codecvt_base::ok;
  318. if (__check_facet(_M_codecvt).always_noconv())
  319. {
  320. __ilen = _M_file.xsgetn(reinterpret_cast<char*>(this->eback()),
  321. __buflen);
  322. if (__ilen == 0)
  323. __got_eof = true;
  324. }
  325. else
  326. {
  327. // Worst-case number of external bytes.
  328. // XXX Not done encoding() == -1.
  329. const int __enc = _M_codecvt->encoding();
  330. streamsize __blen; // Minimum buffer size.
  331. streamsize __rlen; // Number of chars to read.
  332. if (__enc > 0)
  333. __blen = __rlen = __buflen * __enc;
  334. else
  335. {
  336. __blen = __buflen + _M_codecvt->max_length() - 1;
  337. __rlen = __buflen;
  338. }
  339. const streamsize __remainder = _M_ext_end - _M_ext_next;
  340. __rlen = __rlen > __remainder ? __rlen - __remainder : 0;
  341. // An imbue in 'read' mode implies first converting the external
  342. // chars already present.
  343. if (_M_reading && this->egptr() == this->eback() && __remainder)
  344. __rlen = 0;
  345. // Allocate buffer if necessary and move unconverted
  346. // bytes to front.
  347. if (_M_ext_buf_size < __blen)
  348. {
  349. char* __buf = new char[__blen];
  350. if (__remainder)
  351. __builtin_memcpy(__buf, _M_ext_next, __remainder);
  352. delete [] _M_ext_buf;
  353. _M_ext_buf = __buf;
  354. _M_ext_buf_size = __blen;
  355. }
  356. else if (__remainder)
  357. __builtin_memmove(_M_ext_buf, _M_ext_next, __remainder);
  358. _M_ext_next = _M_ext_buf;
  359. _M_ext_end = _M_ext_buf + __remainder;
  360. _M_state_last = _M_state_cur;
  361. do
  362. {
  363. if (__rlen > 0)
  364. {
  365. // Sanity check!
  366. // This may fail if the return value of
  367. // codecvt::max_length() is bogus.
  368. if (_M_ext_end - _M_ext_buf + __rlen > _M_ext_buf_size)
  369. {
  370. __throw_ios_failure(__N("basic_filebuf::underflow "
  371. "codecvt::max_length() "
  372. "is not valid"));
  373. }
  374. streamsize __elen = _M_file.xsgetn(_M_ext_end, __rlen);
  375. if (__elen == 0)
  376. __got_eof = true;
  377. else if (__elen == -1)
  378. break;
  379. _M_ext_end += __elen;
  380. }
  381. char_type* __iend = this->eback();
  382. if (_M_ext_next < _M_ext_end)
  383. __r = _M_codecvt->in(_M_state_cur, _M_ext_next,
  384. _M_ext_end, _M_ext_next,
  385. this->eback(),
  386. this->eback() + __buflen, __iend);
  387. if (__r == codecvt_base::noconv)
  388. {
  389. size_t __avail = _M_ext_end - _M_ext_buf;
  390. __ilen = std::min(__avail, __buflen);
  391. traits_type::copy(this->eback(),
  392. reinterpret_cast<char_type*>
  393. (_M_ext_buf), __ilen);
  394. _M_ext_next = _M_ext_buf + __ilen;
  395. }
  396. else
  397. __ilen = __iend - this->eback();
  398. // _M_codecvt->in may return error while __ilen > 0: this is
  399. // ok, and actually occurs in case of mixed encodings (e.g.,
  400. // XML files).
  401. if (__r == codecvt_base::error)
  402. break;
  403. __rlen = 1;
  404. }
  405. while (__ilen == 0 && !__got_eof);
  406. }
  407. if (__ilen > 0)
  408. {
  409. _M_set_buffer(__ilen);
  410. _M_reading = true;
  411. __ret = traits_type::to_int_type(*this->gptr());
  412. }
  413. else if (__got_eof)
  414. {
  415. // If the actual end of file is reached, set 'uncommitted'
  416. // mode, thus allowing an immediate write without an
  417. // intervening seek.
  418. _M_set_buffer(-1);
  419. _M_reading = false;
  420. // However, reaching it while looping on partial means that
  421. // the file has got an incomplete character.
  422. if (__r == codecvt_base::partial)
  423. __throw_ios_failure(__N("basic_filebuf::underflow "
  424. "incomplete character in file"));
  425. }
  426. else if (__r == codecvt_base::error)
  427. __throw_ios_failure(__N("basic_filebuf::underflow "
  428. "invalid byte sequence in file"));
  429. else
  430. __throw_ios_failure(__N("basic_filebuf::underflow "
  431. "error reading the file"), errno);
  432. }
  433. return __ret;
  434. }
  435. template<typename _CharT, typename _Traits>
  436. typename basic_filebuf<_CharT, _Traits>::int_type
  437. basic_filebuf<_CharT, _Traits>::
  438. pbackfail(int_type __i)
  439. {
  440. int_type __ret = traits_type::eof();
  441. const bool __testin = _M_mode & ios_base::in;
  442. if (__testin)
  443. {
  444. if (_M_writing)
  445. {
  446. if (overflow() == traits_type::eof())
  447. return __ret;
  448. _M_set_buffer(-1);
  449. _M_writing = false;
  450. }
  451. // Remember whether the pback buffer is active, otherwise below
  452. // we may try to store in it a second char (libstdc++/9761).
  453. const bool __testpb = _M_pback_init;
  454. const bool __testeof = traits_type::eq_int_type(__i, __ret);
  455. int_type __tmp;
  456. if (this->eback() < this->gptr())
  457. {
  458. this->gbump(-1);
  459. __tmp = traits_type::to_int_type(*this->gptr());
  460. }
  461. else if (this->seekoff(-1, ios_base::cur) != pos_type(off_type(-1)))
  462. {
  463. __tmp = this->underflow();
  464. if (traits_type::eq_int_type(__tmp, __ret))
  465. return __ret;
  466. }
  467. else
  468. {
  469. // At the beginning of the buffer, need to make a
  470. // putback position available. But the seek may fail
  471. // (f.i., at the beginning of a file, see
  472. // libstdc++/9439) and in that case we return
  473. // traits_type::eof().
  474. return __ret;
  475. }
  476. // Try to put back __i into input sequence in one of three ways.
  477. // Order these tests done in is unspecified by the standard.
  478. if (!__testeof && traits_type::eq_int_type(__i, __tmp))
  479. __ret = __i;
  480. else if (__testeof)
  481. __ret = traits_type::not_eof(__i);
  482. else if (!__testpb)
  483. {
  484. _M_create_pback();
  485. _M_reading = true;
  486. *this->gptr() = traits_type::to_char_type(__i);
  487. __ret = __i;
  488. }
  489. }
  490. return __ret;
  491. }
  492. template<typename _CharT, typename _Traits>
  493. typename basic_filebuf<_CharT, _Traits>::int_type
  494. basic_filebuf<_CharT, _Traits>::
  495. overflow(int_type __c)
  496. {
  497. int_type __ret = traits_type::eof();
  498. const bool __testeof = traits_type::eq_int_type(__c, __ret);
  499. const bool __testout = (_M_mode & ios_base::out
  500. || _M_mode & ios_base::app);
  501. if (__testout)
  502. {
  503. if (_M_reading)
  504. {
  505. _M_destroy_pback();
  506. const int __gptr_off = _M_get_ext_pos(_M_state_last);
  507. if (_M_seek(__gptr_off, ios_base::cur, _M_state_last)
  508. == pos_type(off_type(-1)))
  509. return __ret;
  510. }
  511. if (this->pbase() < this->pptr())
  512. {
  513. // If appropriate, append the overflow char.
  514. if (!__testeof)
  515. {
  516. *this->pptr() = traits_type::to_char_type(__c);
  517. this->pbump(1);
  518. }
  519. // Convert pending sequence to external representation,
  520. // and output.
  521. if (_M_convert_to_external(this->pbase(),
  522. this->pptr() - this->pbase()))
  523. {
  524. _M_set_buffer(0);
  525. __ret = traits_type::not_eof(__c);
  526. }
  527. }
  528. else if (_M_buf_size > 1)
  529. {
  530. // Overflow in 'uncommitted' mode: set _M_writing, set
  531. // the buffer to the initial 'write' mode, and put __c
  532. // into the buffer.
  533. _M_set_buffer(0);
  534. _M_writing = true;
  535. if (!__testeof)
  536. {
  537. *this->pptr() = traits_type::to_char_type(__c);
  538. this->pbump(1);
  539. }
  540. __ret = traits_type::not_eof(__c);
  541. }
  542. else
  543. {
  544. // Unbuffered.
  545. char_type __conv = traits_type::to_char_type(__c);
  546. if (__testeof || _M_convert_to_external(&__conv, 1))
  547. {
  548. _M_writing = true;
  549. __ret = traits_type::not_eof(__c);
  550. }
  551. }
  552. }
  553. return __ret;
  554. }
  555. template<typename _CharT, typename _Traits>
  556. bool
  557. basic_filebuf<_CharT, _Traits>::
  558. _M_convert_to_external(_CharT* __ibuf, streamsize __ilen)
  559. {
  560. // Sizes of external and pending output.
  561. streamsize __elen;
  562. streamsize __plen;
  563. if (__check_facet(_M_codecvt).always_noconv())
  564. {
  565. __elen = _M_file.xsputn(reinterpret_cast<char*>(__ibuf), __ilen);
  566. __plen = __ilen;
  567. }
  568. else
  569. {
  570. // Worst-case number of external bytes needed.
  571. // XXX Not done encoding() == -1.
  572. streamsize __blen = __ilen * _M_codecvt->max_length();
  573. char* __buf = static_cast<char*>(__builtin_alloca(__blen));
  574. char* __bend;
  575. const char_type* __iend;
  576. codecvt_base::result __r;
  577. __r = _M_codecvt->out(_M_state_cur, __ibuf, __ibuf + __ilen,
  578. __iend, __buf, __buf + __blen, __bend);
  579. if (__r == codecvt_base::ok || __r == codecvt_base::partial)
  580. __blen = __bend - __buf;
  581. else if (__r == codecvt_base::noconv)
  582. {
  583. // Same as the always_noconv case above.
  584. __buf = reinterpret_cast<char*>(__ibuf);
  585. __blen = __ilen;
  586. }
  587. else
  588. __throw_ios_failure(__N("basic_filebuf::_M_convert_to_external "
  589. "conversion error"));
  590. __elen = _M_file.xsputn(__buf, __blen);
  591. __plen = __blen;
  592. // Try once more for partial conversions.
  593. if (__r == codecvt_base::partial && __elen == __plen)
  594. {
  595. const char_type* __iresume = __iend;
  596. streamsize __rlen = this->pptr() - __iend;
  597. __r = _M_codecvt->out(_M_state_cur, __iresume,
  598. __iresume + __rlen, __iend, __buf,
  599. __buf + __blen, __bend);
  600. if (__r != codecvt_base::error)
  601. {
  602. __rlen = __bend - __buf;
  603. __elen = _M_file.xsputn(__buf, __rlen);
  604. __plen = __rlen;
  605. }
  606. else
  607. __throw_ios_failure(__N("basic_filebuf::_M_convert_to_external "
  608. "conversion error"));
  609. }
  610. }
  611. return __elen == __plen;
  612. }
  613. template<typename _CharT, typename _Traits>
  614. streamsize
  615. basic_filebuf<_CharT, _Traits>::
  616. xsgetn(_CharT* __s, streamsize __n)
  617. {
  618. // Clear out pback buffer before going on to the real deal...
  619. streamsize __ret = 0;
  620. if (_M_pback_init)
  621. {
  622. if (__n > 0 && this->gptr() == this->eback())
  623. {
  624. *__s++ = *this->gptr(); // emulate non-underflowing sbumpc
  625. this->gbump(1);
  626. __ret = 1;
  627. --__n;
  628. }
  629. _M_destroy_pback();
  630. }
  631. else if (_M_writing)
  632. {
  633. if (overflow() == traits_type::eof())
  634. return __ret;
  635. _M_set_buffer(-1);
  636. _M_writing = false;
  637. }
  638. // Optimization in the always_noconv() case, to be generalized in the
  639. // future: when __n > __buflen we read directly instead of using the
  640. // buffer repeatedly.
  641. const bool __testin = _M_mode & ios_base::in;
  642. const streamsize __buflen = _M_buf_size > 1 ? _M_buf_size - 1 : 1;
  643. if (__n > __buflen && __check_facet(_M_codecvt).always_noconv()
  644. && __testin)
  645. {
  646. // First, copy the chars already present in the buffer.
  647. const streamsize __avail = this->egptr() - this->gptr();
  648. if (__avail != 0)
  649. {
  650. traits_type::copy(__s, this->gptr(), __avail);
  651. __s += __avail;
  652. this->setg(this->eback(), this->gptr() + __avail, this->egptr());
  653. __ret += __avail;
  654. __n -= __avail;
  655. }
  656. // Need to loop in case of short reads (relatively common
  657. // with pipes).
  658. streamsize __len;
  659. for (;;)
  660. {
  661. __len = _M_file.xsgetn(reinterpret_cast<char*>(__s), __n);
  662. if (__len == -1)
  663. __throw_ios_failure(__N("basic_filebuf::xsgetn "
  664. "error reading the file"), errno);
  665. if (__len == 0)
  666. break;
  667. __n -= __len;
  668. __ret += __len;
  669. if (__n == 0)
  670. break;
  671. __s += __len;
  672. }
  673. if (__n == 0)
  674. {
  675. // Set _M_reading. Buffer is already in initial 'read' mode.
  676. _M_reading = true;
  677. }
  678. else if (__len == 0)
  679. {
  680. // If end of file is reached, set 'uncommitted'
  681. // mode, thus allowing an immediate write without
  682. // an intervening seek.
  683. _M_set_buffer(-1);
  684. _M_reading = false;
  685. }
  686. }
  687. else
  688. __ret += __streambuf_type::xsgetn(__s, __n);
  689. return __ret;
  690. }
  691. template<typename _CharT, typename _Traits>
  692. streamsize
  693. basic_filebuf<_CharT, _Traits>::
  694. xsputn(const _CharT* __s, streamsize __n)
  695. {
  696. streamsize __ret = 0;
  697. // Optimization in the always_noconv() case, to be generalized in the
  698. // future: when __n is sufficiently large we write directly instead of
  699. // using the buffer.
  700. const bool __testout = (_M_mode & ios_base::out
  701. || _M_mode & ios_base::app);
  702. if (__check_facet(_M_codecvt).always_noconv()
  703. && __testout && !_M_reading)
  704. {
  705. // Measurement would reveal the best choice.
  706. const streamsize __chunk = 1ul << 10;
  707. streamsize __bufavail = this->epptr() - this->pptr();
  708. // Don't mistake 'uncommitted' mode buffered with unbuffered.
  709. if (!_M_writing && _M_buf_size > 1)
  710. __bufavail = _M_buf_size - 1;
  711. const streamsize __limit = std::min(__chunk, __bufavail);
  712. if (__n >= __limit)
  713. {
  714. const streamsize __buffill = this->pptr() - this->pbase();
  715. const char* __buf = reinterpret_cast<const char*>(this->pbase());
  716. __ret = _M_file.xsputn_2(__buf, __buffill,
  717. reinterpret_cast<const char*>(__s),
  718. __n);
  719. if (__ret == __buffill + __n)
  720. {
  721. _M_set_buffer(0);
  722. _M_writing = true;
  723. }
  724. if (__ret > __buffill)
  725. __ret -= __buffill;
  726. else
  727. __ret = 0;
  728. }
  729. else
  730. __ret = __streambuf_type::xsputn(__s, __n);
  731. }
  732. else
  733. __ret = __streambuf_type::xsputn(__s, __n);
  734. return __ret;
  735. }
  736. template<typename _CharT, typename _Traits>
  737. typename basic_filebuf<_CharT, _Traits>::__streambuf_type*
  738. basic_filebuf<_CharT, _Traits>::
  739. setbuf(char_type* __s, streamsize __n)
  740. {
  741. if (!this->is_open())
  742. {
  743. if (__s == 0 && __n == 0)
  744. _M_buf_size = 1;
  745. else if (__s && __n > 0)
  746. {
  747. // This is implementation-defined behavior, and assumes that
  748. // an external char_type array of length __n exists and has
  749. // been pre-allocated. If this is not the case, things will
  750. // quickly blow up. When __n > 1, __n - 1 positions will be
  751. // used for the get area, __n - 1 for the put area and 1
  752. // position to host the overflow char of a full put area.
  753. // When __n == 1, 1 position will be used for the get area
  754. // and 0 for the put area, as in the unbuffered case above.
  755. _M_buf = __s;
  756. _M_buf_size = __n;
  757. }
  758. }
  759. return this;
  760. }
  761. // According to 27.8.1.4 p11 - 13, seekoff should ignore the last
  762. // argument (of type openmode).
  763. template<typename _CharT, typename _Traits>
  764. typename basic_filebuf<_CharT, _Traits>::pos_type
  765. basic_filebuf<_CharT, _Traits>::
  766. seekoff(off_type __off, ios_base::seekdir __way, ios_base::openmode)
  767. {
  768. int __width = 0;
  769. if (_M_codecvt)
  770. __width = _M_codecvt->encoding();
  771. if (__width < 0)
  772. __width = 0;
  773. pos_type __ret = pos_type(off_type(-1));
  774. const bool __testfail = __off != 0 && __width <= 0;
  775. if (this->is_open() && !__testfail)
  776. {
  777. // tellg and tellp queries do not affect any state, unless
  778. // ! always_noconv and the put sequence is not empty.
  779. // In that case, determining the position requires converting the
  780. // put sequence. That doesn't use ext_buf, so requires a flush.
  781. bool __no_movement = __way == ios_base::cur && __off == 0
  782. && (!_M_writing || _M_codecvt->always_noconv());
  783. // Ditch any pback buffers to avoid confusion.
  784. if (!__no_movement)
  785. _M_destroy_pback();
  786. // Correct state at destination. Note that this is the correct
  787. // state for the current position during output, because
  788. // codecvt::unshift() returns the state to the initial state.
  789. // This is also the correct state at the end of the file because
  790. // an unshift sequence should have been written at the end.
  791. __state_type __state = _M_state_beg;
  792. off_type __computed_off = __off * __width;
  793. if (_M_reading && __way == ios_base::cur)
  794. {
  795. __state = _M_state_last;
  796. __computed_off += _M_get_ext_pos(__state);
  797. }
  798. if (!__no_movement)
  799. __ret = _M_seek(__computed_off, __way, __state);
  800. else
  801. {
  802. if (_M_writing)
  803. __computed_off = this->pptr() - this->pbase();
  804. off_type __file_off = _M_file.seekoff(0, ios_base::cur);
  805. if (__file_off != off_type(-1))
  806. {
  807. __ret = __file_off + __computed_off;
  808. __ret.state(__state);
  809. }
  810. }
  811. }
  812. return __ret;
  813. }
  814. // _GLIBCXX_RESOLVE_LIB_DEFECTS
  815. // 171. Strange seekpos() semantics due to joint position
  816. // According to the resolution of DR 171, seekpos should ignore the last
  817. // argument (of type openmode).
  818. template<typename _CharT, typename _Traits>
  819. typename basic_filebuf<_CharT, _Traits>::pos_type
  820. basic_filebuf<_CharT, _Traits>::
  821. seekpos(pos_type __pos, ios_base::openmode)
  822. {
  823. pos_type __ret = pos_type(off_type(-1));
  824. if (this->is_open())
  825. {
  826. // Ditch any pback buffers to avoid confusion.
  827. _M_destroy_pback();
  828. __ret = _M_seek(off_type(__pos), ios_base::beg, __pos.state());
  829. }
  830. return __ret;
  831. }
  832. template<typename _CharT, typename _Traits>
  833. typename basic_filebuf<_CharT, _Traits>::pos_type
  834. basic_filebuf<_CharT, _Traits>::
  835. _M_seek(off_type __off, ios_base::seekdir __way, __state_type __state)
  836. {
  837. pos_type __ret = pos_type(off_type(-1));
  838. if (_M_terminate_output())
  839. {
  840. off_type __file_off = _M_file.seekoff(__off, __way);
  841. if (__file_off != off_type(-1))
  842. {
  843. _M_reading = false;
  844. _M_writing = false;
  845. _M_ext_next = _M_ext_end = _M_ext_buf;
  846. _M_set_buffer(-1);
  847. _M_state_cur = __state;
  848. __ret = __file_off;
  849. __ret.state(_M_state_cur);
  850. }
  851. }
  852. return __ret;
  853. }
  854. // Returns the distance from the end of the ext buffer to the point
  855. // corresponding to gptr(). This is a negative value. Updates __state
  856. // from eback() correspondence to gptr().
  857. template<typename _CharT, typename _Traits>
  858. int basic_filebuf<_CharT, _Traits>::
  859. _M_get_ext_pos(__state_type& __state)
  860. {
  861. if (_M_codecvt->always_noconv())
  862. return this->gptr() - this->egptr();
  863. else
  864. {
  865. // Calculate offset from _M_ext_buf that corresponds to
  866. // gptr(). Precondition: __state == _M_state_last, which
  867. // corresponds to eback().
  868. const int __gptr_off =
  869. _M_codecvt->length(__state, _M_ext_buf, _M_ext_next,
  870. this->gptr() - this->eback());
  871. return _M_ext_buf + __gptr_off - _M_ext_end;
  872. }
  873. }
  874. template<typename _CharT, typename _Traits>
  875. bool
  876. basic_filebuf<_CharT, _Traits>::
  877. _M_terminate_output()
  878. {
  879. // Part one: update the output sequence.
  880. bool __testvalid = true;
  881. if (this->pbase() < this->pptr())
  882. {
  883. const int_type __tmp = this->overflow();
  884. if (traits_type::eq_int_type(__tmp, traits_type::eof()))
  885. __testvalid = false;
  886. }
  887. // Part two: output unshift sequence.
  888. if (_M_writing && !__check_facet(_M_codecvt).always_noconv()
  889. && __testvalid)
  890. {
  891. // Note: this value is arbitrary, since there is no way to
  892. // get the length of the unshift sequence from codecvt,
  893. // without calling unshift.
  894. const size_t __blen = 128;
  895. char __buf[__blen];
  896. codecvt_base::result __r;
  897. streamsize __ilen = 0;
  898. do
  899. {
  900. char* __next;
  901. __r = _M_codecvt->unshift(_M_state_cur, __buf,
  902. __buf + __blen, __next);
  903. if (__r == codecvt_base::error)
  904. __testvalid = false;
  905. else if (__r == codecvt_base::ok ||
  906. __r == codecvt_base::partial)
  907. {
  908. __ilen = __next - __buf;
  909. if (__ilen > 0)
  910. {
  911. const streamsize __elen = _M_file.xsputn(__buf, __ilen);
  912. if (__elen != __ilen)
  913. __testvalid = false;
  914. }
  915. }
  916. }
  917. while (__r == codecvt_base::partial && __ilen > 0 && __testvalid);
  918. if (__testvalid)
  919. {
  920. // This second call to overflow() is required by the standard,
  921. // but it's not clear why it's needed, since the output buffer
  922. // should be empty by this point (it should have been emptied
  923. // in the first call to overflow()).
  924. const int_type __tmp = this->overflow();
  925. if (traits_type::eq_int_type(__tmp, traits_type::eof()))
  926. __testvalid = false;
  927. }
  928. }
  929. return __testvalid;
  930. }
  931. template<typename _CharT, typename _Traits>
  932. int
  933. basic_filebuf<_CharT, _Traits>::
  934. sync()
  935. {
  936. // Make sure that the internal buffer resyncs its idea of
  937. // the file position with the external file.
  938. int __ret = 0;
  939. if (this->pbase() < this->pptr())
  940. {
  941. const int_type __tmp = this->overflow();
  942. if (traits_type::eq_int_type(__tmp, traits_type::eof()))
  943. __ret = -1;
  944. }
  945. return __ret;
  946. }
  947. template<typename _CharT, typename _Traits>
  948. void
  949. basic_filebuf<_CharT, _Traits>::
  950. imbue(const locale& __loc)
  951. {
  952. bool __testvalid = true;
  953. const __codecvt_type* _M_codecvt_tmp = 0;
  954. if (__builtin_expect(has_facet<__codecvt_type>(__loc), true))
  955. _M_codecvt_tmp = &use_facet<__codecvt_type>(__loc);
  956. if (this->is_open())
  957. {
  958. // encoding() == -1 is ok only at the beginning.
  959. if ((_M_reading || _M_writing)
  960. && __check_facet(_M_codecvt).encoding() == -1)
  961. __testvalid = false;
  962. else
  963. {
  964. if (_M_reading)
  965. {
  966. if (__check_facet(_M_codecvt).always_noconv())
  967. {
  968. if (_M_codecvt_tmp
  969. && !__check_facet(_M_codecvt_tmp).always_noconv())
  970. __testvalid = this->seekoff(0, ios_base::cur, _M_mode)
  971. != pos_type(off_type(-1));
  972. }
  973. else
  974. {
  975. // External position corresponding to gptr().
  976. _M_ext_next = _M_ext_buf
  977. + _M_codecvt->length(_M_state_last, _M_ext_buf,
  978. _M_ext_next,
  979. this->gptr() - this->eback());
  980. const streamsize __remainder = _M_ext_end - _M_ext_next;
  981. if (__remainder)
  982. __builtin_memmove(_M_ext_buf, _M_ext_next, __remainder);
  983. _M_ext_next = _M_ext_buf;
  984. _M_ext_end = _M_ext_buf + __remainder;
  985. _M_set_buffer(-1);
  986. _M_state_last = _M_state_cur = _M_state_beg;
  987. }
  988. }
  989. else if (_M_writing && (__testvalid = _M_terminate_output()))
  990. _M_set_buffer(-1);
  991. }
  992. }
  993. if (__testvalid)
  994. _M_codecvt = _M_codecvt_tmp;
  995. else
  996. _M_codecvt = 0;
  997. }
  998. // Inhibit implicit instantiations for required instantiations,
  999. // which are defined via explicit instantiations elsewhere.
  1000. #if _GLIBCXX_EXTERN_TEMPLATE
  1001. extern template class basic_filebuf<char>;
  1002. extern template class basic_ifstream<char>;
  1003. extern template class basic_ofstream<char>;
  1004. extern template class basic_fstream<char>;
  1005. #ifdef _GLIBCXX_USE_WCHAR_T
  1006. extern template class basic_filebuf<wchar_t>;
  1007. extern template class basic_ifstream<wchar_t>;
  1008. extern template class basic_ofstream<wchar_t>;
  1009. extern template class basic_fstream<wchar_t>;
  1010. #endif
  1011. #endif
  1012. _GLIBCXX_END_NAMESPACE_VERSION
  1013. } // namespace std
  1014. #endif