xref: /openbsd-src/gnu/lib/libstdc++/libstdc++/src/fstream.cc (revision c2fb321235c8dbfba0909bc43913400e90646ae7)
1 // File based streams -*- C++ -*-
2 
3 // Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003
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 2, or (at your option)
10 // any later version.
11 
12 // This library is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 // GNU General Public License for more details.
16 
17 // You should have received a copy of the GNU General Public License along
18 // with this library; see the file COPYING.  If not, write to the Free
19 // Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
20 // USA.
21 
22 // As a special exception, you may use this file as part of a free software
23 // library without restriction.  Specifically, if other files instantiate
24 // templates or use macros or inline functions from this file, or you compile
25 // this file and link it with other files to produce an executable, this
26 // file does not by itself cause the resulting executable to be covered by
27 // the GNU General Public License.  This exception does not however
28 // invalidate any other reasons why the executable file might be covered by
29 // the GNU General Public License.
30 
31 //
32 // ISO C++ 14882: 27.8  File-based streams
33 //
34 
35 #include <fstream>
36 
37 namespace std
38 {
39   template<>
40     basic_filebuf<char>::int_type
_M_underflow_common(bool __bump)41     basic_filebuf<char>::_M_underflow_common(bool __bump)
42     {
43       int_type __ret = traits_type::eof();
44       bool __testin = _M_mode & ios_base::in;
45       bool __testout = _M_mode & ios_base::out;
46 
47       if (__testin)
48 	{
49 	  // Check for pback madness, and if so swich back to the
50 	  // normal buffers and jet outta here before expensive
51 	  // fileops happen...
52 	  if (_M_pback_init)
53 	    _M_pback_destroy();
54 
55 	  if (_M_in_cur && _M_in_cur < _M_in_end)
56 	    {
57 	      __ret = traits_type::to_int_type(*_M_in_cur);
58 	      if (__bump)
59 		_M_in_cur_move(1);
60 	      return __ret;
61 	    }
62 
63 	  // Sync internal and external buffers.
64 	  // NB: __testget -> __testput as _M_buf_unified here.
65 	  bool __testget = _M_in_cur && _M_in_beg < _M_in_cur;
66 	  bool __testinit = _M_is_indeterminate();
67 	  if (__testget)
68 	    {
69 	      if (__testout)
70 		_M_really_overflow();
71 	      else if (_M_in_cur != _M_filepos)
72 		_M_file.seekoff(_M_in_cur - _M_filepos,
73 				ios_base::cur, ios_base::in);
74 	    }
75 
76 	  if (__testinit || __testget)
77 	    {
78 	      streamsize __elen = 0;
79 	      streamsize __ilen = 0;
80 	      __elen = _M_file.xsgetn(reinterpret_cast<char*>(_M_in_beg),
81 				      _M_buf_size);
82 	      __ilen = __elen;
83 
84 	      if (0 < __ilen)
85 		{
86 		  _M_set_determinate(__ilen);
87 		  if (__testout)
88 		    _M_out_cur = _M_in_cur;
89 		  __ret = traits_type::to_int_type(*_M_in_cur);
90 		  if (__bump)
91 		    _M_in_cur_move(1);
92 		  else if (_M_buf_size == 1)
93 		    {
94 		      // If we are synced with stdio, we have to unget the
95 		      // character we just read so that the file pointer
96 		      // doesn't move.
97 		      _M_file.sys_ungetc(traits_type::to_int_type(*_M_in_cur));
98 		      _M_set_indeterminate();
99 		    }
100 		}
101 	    }
102 	}
103       _M_last_overflowed = false;
104       return __ret;
105     }
106 
107 #if defined(_GLIBCPP_USE_WCHAR_T) || defined(_GLIBCPP_USE_TYPE_WCHAR_T)
108   template<>
109     basic_filebuf<wchar_t>::int_type
_M_underflow_common(bool __bump)110     basic_filebuf<wchar_t>::_M_underflow_common(bool __bump)
111     {
112       int_type __ret = traits_type::eof();
113       bool __testin = _M_mode & ios_base::in;
114       bool __testout = _M_mode & ios_base::out;
115 
116       if (__testin)
117 	{
118 	  // Check for pback madness, and if so swich back to the
119 	  // normal buffers and jet outta here before expensive
120 	  // fileops happen...
121 	  if (_M_pback_init)
122 	    _M_pback_destroy();
123 
124 	  if (_M_in_cur && _M_in_cur < _M_in_end)
125 	    {
126 	      __ret = traits_type::to_int_type(*_M_in_cur);
127 	      if (__bump)
128 		_M_in_cur_move(1);
129 	      return __ret;
130 	    }
131 
132 	  // Sync internal and external buffers.
133 	  // NB: __testget -> __testput as _M_buf_unified here.
134 	  bool __testget = _M_in_cur && _M_in_beg < _M_in_cur;
135 	  bool __testinit = _M_is_indeterminate();
136 	  if (__testget)
137 	    {
138 	      if (__testout)
139 		_M_really_overflow();
140 	      else if (_M_in_cur != _M_filepos)
141 		_M_file.seekoff(_M_in_cur - _M_filepos,
142 				ios_base::cur, ios_base::in);
143 	    }
144 
145 	  if (__testinit || __testget)
146 	    {
147 	      const locale __loc = this->getloc();
148 	      const __codecvt_type& __cvt = use_facet<__codecvt_type>(__loc);
149 
150 	      streamsize __elen = 0;
151 	      streamsize __ilen = 0;
152 	      if (__cvt.always_noconv())
153 		{
154 		  __elen = _M_file.xsgetn(reinterpret_cast<char*>(_M_in_beg),
155 					  _M_buf_size);
156 		  __ilen = __elen;
157 		}
158 	      else
159 		{
160 		  char* __buf = static_cast<char*>(__builtin_alloca(_M_buf_size));
161 		  __elen = _M_file.xsgetn(__buf, _M_buf_size);
162 
163 		  const char* __eend;
164 		  char_type* __iend;
165 		  codecvt_base::result __r;
166 		  __r = __cvt.in(_M_state_cur, __buf,
167 				 __buf + __elen, __eend, _M_in_beg,
168 				 _M_in_beg + _M_buf_size, __iend);
169 		  if (__r == codecvt_base::ok)
170 		    __ilen = __iend - _M_in_beg;
171 		  else
172 		    {
173 		      // Unwind.
174 		      __ilen = 0;
175 		      _M_file.seekoff(-__elen, ios_base::cur, ios_base::in);
176 		    }
177 		}
178 
179 	      if (0 < __ilen)
180 		{
181 		  _M_set_determinate(__ilen);
182 		  if (__testout)
183 		    _M_out_cur = _M_in_cur;
184 		  __ret = traits_type::to_int_type(*_M_in_cur);
185 		  if (__bump)
186 		    _M_in_cur_move(1);
187 		  else if (_M_buf_size == 1)
188 		    {
189 		      // If we are synced with stdio, we have to unget the
190 		      // character we just read so that the file pointer
191 		      // doesn't move.
192 		      _M_file.sys_ungetc(traits_type::to_int_type(*_M_in_cur));
193 		      _M_set_indeterminate();
194 		    }
195 		}
196 	    }
197 	}
198       _M_last_overflowed = false;
199       return __ret;
200     }
201 #endif
202 } // namespace std
203