fstream.tcc 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069
  1. // File based streams -*- C++ -*-
  2. // Copyright (C) 1997-2015 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,
  622. this->egptr());
  623. __ret += __avail;
  624. __n -= __avail;
  625. }
  626. // Need to loop in case of short reads (relatively common
  627. // with pipes).
  628. streamsize __len;
  629. for (;;)
  630. {
  631. __len = _M_file.xsgetn(reinterpret_cast<char*>(__s),
  632. __n);
  633. if (__len == -1)
  634. __throw_ios_failure(__N("basic_filebuf::xsgetn "
  635. "error reading the file"));
  636. if (__len == 0)
  637. break;
  638. __n -= __len;
  639. __ret += __len;
  640. if (__n == 0)
  641. break;
  642. __s += __len;
  643. }
  644. if (__n == 0)
  645. {
  646. _M_set_buffer(0);
  647. _M_reading = true;
  648. }
  649. else if (__len == 0)
  650. {
  651. // If end of file is reached, set 'uncommitted'
  652. // mode, thus allowing an immediate write without
  653. // an intervening seek.
  654. _M_set_buffer(-1);
  655. _M_reading = false;
  656. }
  657. }
  658. else
  659. __ret += __streambuf_type::xsgetn(__s, __n);
  660. return __ret;
  661. }
  662. template<typename _CharT, typename _Traits>
  663. streamsize
  664. basic_filebuf<_CharT, _Traits>::
  665. xsputn(const _CharT* __s, streamsize __n)
  666. {
  667. streamsize __ret = 0;
  668. // Optimization in the always_noconv() case, to be generalized in the
  669. // future: when __n is sufficiently large we write directly instead of
  670. // using the buffer.
  671. const bool __testout = (_M_mode & ios_base::out
  672. || _M_mode & ios_base::app);
  673. if (__check_facet(_M_codecvt).always_noconv()
  674. && __testout && !_M_reading)
  675. {
  676. // Measurement would reveal the best choice.
  677. const streamsize __chunk = 1ul << 10;
  678. streamsize __bufavail = this->epptr() - this->pptr();
  679. // Don't mistake 'uncommitted' mode buffered with unbuffered.
  680. if (!_M_writing && _M_buf_size > 1)
  681. __bufavail = _M_buf_size - 1;
  682. const streamsize __limit = std::min(__chunk, __bufavail);
  683. if (__n >= __limit)
  684. {
  685. const streamsize __buffill = this->pptr() - this->pbase();
  686. const char* __buf = reinterpret_cast<const char*>(this->pbase());
  687. __ret = _M_file.xsputn_2(__buf, __buffill,
  688. reinterpret_cast<const char*>(__s),
  689. __n);
  690. if (__ret == __buffill + __n)
  691. {
  692. _M_set_buffer(0);
  693. _M_writing = true;
  694. }
  695. if (__ret > __buffill)
  696. __ret -= __buffill;
  697. else
  698. __ret = 0;
  699. }
  700. else
  701. __ret = __streambuf_type::xsputn(__s, __n);
  702. }
  703. else
  704. __ret = __streambuf_type::xsputn(__s, __n);
  705. return __ret;
  706. }
  707. template<typename _CharT, typename _Traits>
  708. typename basic_filebuf<_CharT, _Traits>::__streambuf_type*
  709. basic_filebuf<_CharT, _Traits>::
  710. setbuf(char_type* __s, streamsize __n)
  711. {
  712. if (!this->is_open())
  713. {
  714. if (__s == 0 && __n == 0)
  715. _M_buf_size = 1;
  716. else if (__s && __n > 0)
  717. {
  718. // This is implementation-defined behavior, and assumes that
  719. // an external char_type array of length __n exists and has
  720. // been pre-allocated. If this is not the case, things will
  721. // quickly blow up. When __n > 1, __n - 1 positions will be
  722. // used for the get area, __n - 1 for the put area and 1
  723. // position to host the overflow char of a full put area.
  724. // When __n == 1, 1 position will be used for the get area
  725. // and 0 for the put area, as in the unbuffered case above.
  726. _M_buf = __s;
  727. _M_buf_size = __n;
  728. }
  729. }
  730. return this;
  731. }
  732. // According to 27.8.1.4 p11 - 13, seekoff should ignore the last
  733. // argument (of type openmode).
  734. template<typename _CharT, typename _Traits>
  735. typename basic_filebuf<_CharT, _Traits>::pos_type
  736. basic_filebuf<_CharT, _Traits>::
  737. seekoff(off_type __off, ios_base::seekdir __way, ios_base::openmode)
  738. {
  739. int __width = 0;
  740. if (_M_codecvt)
  741. __width = _M_codecvt->encoding();
  742. if (__width < 0)
  743. __width = 0;
  744. pos_type __ret = pos_type(off_type(-1));
  745. const bool __testfail = __off != 0 && __width <= 0;
  746. if (this->is_open() && !__testfail)
  747. {
  748. // tellg and tellp queries do not affect any state, unless
  749. // ! always_noconv and the put sequence is not empty.
  750. // In that case, determining the position requires converting the
  751. // put sequence. That doesn't use ext_buf, so requires a flush.
  752. bool __no_movement = __way == ios_base::cur && __off == 0
  753. && (!_M_writing || _M_codecvt->always_noconv());
  754. // Ditch any pback buffers to avoid confusion.
  755. if (!__no_movement)
  756. _M_destroy_pback();
  757. // Correct state at destination. Note that this is the correct
  758. // state for the current position during output, because
  759. // codecvt::unshift() returns the state to the initial state.
  760. // This is also the correct state at the end of the file because
  761. // an unshift sequence should have been written at the end.
  762. __state_type __state = _M_state_beg;
  763. off_type __computed_off = __off * __width;
  764. if (_M_reading && __way == ios_base::cur)
  765. {
  766. __state = _M_state_last;
  767. __computed_off += _M_get_ext_pos(__state);
  768. }
  769. if (!__no_movement)
  770. __ret = _M_seek(__computed_off, __way, __state);
  771. else
  772. {
  773. if (_M_writing)
  774. __computed_off = this->pptr() - this->pbase();
  775. off_type __file_off = _M_file.seekoff(0, ios_base::cur);
  776. if (__file_off != off_type(-1))
  777. {
  778. __ret = __file_off + __computed_off;
  779. __ret.state(__state);
  780. }
  781. }
  782. }
  783. return __ret;
  784. }
  785. // _GLIBCXX_RESOLVE_LIB_DEFECTS
  786. // 171. Strange seekpos() semantics due to joint position
  787. // According to the resolution of DR 171, seekpos should ignore the last
  788. // argument (of type openmode).
  789. template<typename _CharT, typename _Traits>
  790. typename basic_filebuf<_CharT, _Traits>::pos_type
  791. basic_filebuf<_CharT, _Traits>::
  792. seekpos(pos_type __pos, ios_base::openmode)
  793. {
  794. pos_type __ret = pos_type(off_type(-1));
  795. if (this->is_open())
  796. {
  797. // Ditch any pback buffers to avoid confusion.
  798. _M_destroy_pback();
  799. __ret = _M_seek(off_type(__pos), ios_base::beg, __pos.state());
  800. }
  801. return __ret;
  802. }
  803. template<typename _CharT, typename _Traits>
  804. typename basic_filebuf<_CharT, _Traits>::pos_type
  805. basic_filebuf<_CharT, _Traits>::
  806. _M_seek(off_type __off, ios_base::seekdir __way, __state_type __state)
  807. {
  808. pos_type __ret = pos_type(off_type(-1));
  809. if (_M_terminate_output())
  810. {
  811. off_type __file_off = _M_file.seekoff(__off, __way);
  812. if (__file_off != off_type(-1))
  813. {
  814. _M_reading = false;
  815. _M_writing = false;
  816. _M_ext_next = _M_ext_end = _M_ext_buf;
  817. _M_set_buffer(-1);
  818. _M_state_cur = __state;
  819. __ret = __file_off;
  820. __ret.state(_M_state_cur);
  821. }
  822. }
  823. return __ret;
  824. }
  825. // Returns the distance from the end of the ext buffer to the point
  826. // corresponding to gptr(). This is a negative value. Updates __state
  827. // from eback() correspondence to gptr().
  828. template<typename _CharT, typename _Traits>
  829. int basic_filebuf<_CharT, _Traits>::
  830. _M_get_ext_pos(__state_type& __state)
  831. {
  832. if (_M_codecvt->always_noconv())
  833. return this->gptr() - this->egptr();
  834. else
  835. {
  836. // Calculate offset from _M_ext_buf that corresponds to
  837. // gptr(). Precondition: __state == _M_state_last, which
  838. // corresponds to eback().
  839. const int __gptr_off =
  840. _M_codecvt->length(__state, _M_ext_buf, _M_ext_next,
  841. this->gptr() - this->eback());
  842. return _M_ext_buf + __gptr_off - _M_ext_end;
  843. }
  844. }
  845. template<typename _CharT, typename _Traits>
  846. bool
  847. basic_filebuf<_CharT, _Traits>::
  848. _M_terminate_output()
  849. {
  850. // Part one: update the output sequence.
  851. bool __testvalid = true;
  852. if (this->pbase() < this->pptr())
  853. {
  854. const int_type __tmp = this->overflow();
  855. if (traits_type::eq_int_type(__tmp, traits_type::eof()))
  856. __testvalid = false;
  857. }
  858. // Part two: output unshift sequence.
  859. if (_M_writing && !__check_facet(_M_codecvt).always_noconv()
  860. && __testvalid)
  861. {
  862. // Note: this value is arbitrary, since there is no way to
  863. // get the length of the unshift sequence from codecvt,
  864. // without calling unshift.
  865. const size_t __blen = 128;
  866. char __buf[__blen];
  867. codecvt_base::result __r;
  868. streamsize __ilen = 0;
  869. do
  870. {
  871. char* __next;
  872. __r = _M_codecvt->unshift(_M_state_cur, __buf,
  873. __buf + __blen, __next);
  874. if (__r == codecvt_base::error)
  875. __testvalid = false;
  876. else if (__r == codecvt_base::ok ||
  877. __r == codecvt_base::partial)
  878. {
  879. __ilen = __next - __buf;
  880. if (__ilen > 0)
  881. {
  882. const streamsize __elen = _M_file.xsputn(__buf, __ilen);
  883. if (__elen != __ilen)
  884. __testvalid = false;
  885. }
  886. }
  887. }
  888. while (__r == codecvt_base::partial && __ilen > 0 && __testvalid);
  889. if (__testvalid)
  890. {
  891. // This second call to overflow() is required by the standard,
  892. // but it's not clear why it's needed, since the output buffer
  893. // should be empty by this point (it should have been emptied
  894. // in the first call to overflow()).
  895. const int_type __tmp = this->overflow();
  896. if (traits_type::eq_int_type(__tmp, traits_type::eof()))
  897. __testvalid = false;
  898. }
  899. }
  900. return __testvalid;
  901. }
  902. template<typename _CharT, typename _Traits>
  903. int
  904. basic_filebuf<_CharT, _Traits>::
  905. sync()
  906. {
  907. // Make sure that the internal buffer resyncs its idea of
  908. // the file position with the external file.
  909. int __ret = 0;
  910. if (this->pbase() < this->pptr())
  911. {
  912. const int_type __tmp = this->overflow();
  913. if (traits_type::eq_int_type(__tmp, traits_type::eof()))
  914. __ret = -1;
  915. }
  916. return __ret;
  917. }
  918. template<typename _CharT, typename _Traits>
  919. void
  920. basic_filebuf<_CharT, _Traits>::
  921. imbue(const locale& __loc)
  922. {
  923. bool __testvalid = true;
  924. const __codecvt_type* _M_codecvt_tmp = 0;
  925. if (__builtin_expect(has_facet<__codecvt_type>(__loc), true))
  926. _M_codecvt_tmp = &use_facet<__codecvt_type>(__loc);
  927. if (this->is_open())
  928. {
  929. // encoding() == -1 is ok only at the beginning.
  930. if ((_M_reading || _M_writing)
  931. && __check_facet(_M_codecvt).encoding() == -1)
  932. __testvalid = false;
  933. else
  934. {
  935. if (_M_reading)
  936. {
  937. if (__check_facet(_M_codecvt).always_noconv())
  938. {
  939. if (_M_codecvt_tmp
  940. && !__check_facet(_M_codecvt_tmp).always_noconv())
  941. __testvalid = this->seekoff(0, ios_base::cur, _M_mode)
  942. != pos_type(off_type(-1));
  943. }
  944. else
  945. {
  946. // External position corresponding to gptr().
  947. _M_ext_next = _M_ext_buf
  948. + _M_codecvt->length(_M_state_last, _M_ext_buf,
  949. _M_ext_next,
  950. this->gptr() - this->eback());
  951. const streamsize __remainder = _M_ext_end - _M_ext_next;
  952. if (__remainder)
  953. __builtin_memmove(_M_ext_buf, _M_ext_next, __remainder);
  954. _M_ext_next = _M_ext_buf;
  955. _M_ext_end = _M_ext_buf + __remainder;
  956. _M_set_buffer(-1);
  957. _M_state_last = _M_state_cur = _M_state_beg;
  958. }
  959. }
  960. else if (_M_writing && (__testvalid = _M_terminate_output()))
  961. _M_set_buffer(-1);
  962. }
  963. }
  964. if (__testvalid)
  965. _M_codecvt = _M_codecvt_tmp;
  966. else
  967. _M_codecvt = 0;
  968. }
  969. // Inhibit implicit instantiations for required instantiations,
  970. // which are defined via explicit instantiations elsewhere.
  971. #if _GLIBCXX_EXTERN_TEMPLATE
  972. extern template class basic_filebuf<char>;
  973. extern template class basic_ifstream<char>;
  974. extern template class basic_ofstream<char>;
  975. extern template class basic_fstream<char>;
  976. #ifdef _GLIBCXX_USE_WCHAR_T
  977. extern template class basic_filebuf<wchar_t>;
  978. extern template class basic_ifstream<wchar_t>;
  979. extern template class basic_ofstream<wchar_t>;
  980. extern template class basic_fstream<wchar_t>;
  981. #endif
  982. #endif
  983. _GLIBCXX_END_NAMESPACE_VERSION
  984. } // namespace std
  985. #endif