fstream.tcc 32 KB

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