fstream.tcc 33 KB

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