fstream.tcc 27 KB

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