This is the mail archive of the
libstdc++@sourceware.cygnus.com
mailing list for the libstdc++ project.
fstream/ostream patch
- To: libstdc++@sourceware.cygnus.com
- Subject: fstream/ostream patch
- From: Phil Edwards <pedwards@jaj.com>
- Date: Thu, 3 Jun 1999 23:18:08 -0400
Some of this discussion may be overkill. Please forgive my long-windedness.
This patch fixes two related problems: first,
OUT << IN.rdbuf();
is supposed to mass-copy the data stream. Currently, op<< taking a
streambuf* makes a copy of IN's buffer on the stack, then calls
_M_fnumput's put() on the buffer[*]. But num_put doesn't have a put()
for char*, only for void*. The void* version assumes that you really
are writing a void* instead of a buffer, casts the pointer to an
unsigned long, and writes the hex value.
As a result, instead of a copy of the buffer, what gets written to
the OUT stream is the address of the stack's character array containing
the buffer. Quite a surprise. :-) This patch to ostream.tcc simply
passes on the char* and size to the streambuf's sputn, same as ostream's
write(char*) currently does.
A simple testcase:
#include <fstream>
int main ()
{
std::ifstream IN ("input_file"); // fill this file with a little text
std::ofstream OUT ("output_file");
OUT << IN.rdbuf() << std::endl;
}
Currently, output_file will contain something like
0xbfff3c40
and a newline. This patch fixes it.
*sigh* This led to the second patch. basic_filebuf's xsputn() tests
for buffer space, and if it needs to, it calls overflow() on the first
incoming character. It then increments retval, as an indication of
"already done one character-unit of work". In the very next block, if
the entire incoming string can fit into the buffer, retval is set to
the incoming buffer size, as an indication of "this is how much work
will be / was done".
That assignment clobbers the previous one, and so an extra character
is always copied (the past-the-end character from the incoming string,
actually), because that overflow character is forgotten. This patch
stores any "work done" during the possible overflow() branch, and later
uses that as a starting point, so that __n and __retval will still be
equal on completion.
(This patch is necessary for the previous one to work. Else your
output_file will contain one garbage character at the end of the file.)
All of the testsuite tests pass, keeping in mind that the filebuf tests
have that 'diff: ain't no such file' error.
[*] Since the data is supposed to be blindly copied, I never read that
section of the standard as meaning that locale-related conversions
should be done anyway... help?
1999-06-03 Phil Edwards <pedwards@ball.com>
* bits/fstream.tcc (basic_filebuf::xsputn): Fix off-by-one count
caused when __testinit is true.
* bits/ostream.tcc (basic_ostream::op<<(streambuf*)): Write buffer
using rdbuf()->sputn rather than _M_fnumput->put.
Index: fstream.tcc
===================================================================
RCS file: /cvs/libstdc++/libstdc++/bits/fstream.tcc,v
retrieving revision 1.21
diff -c -3 -p -r1.21 fstream.tcc
*** fstream.tcc 1999/06/03 00:47:35 1.21
--- fstream.tcc 1999/06/04 02:35:06
*************** namespace std
*** 455,467 ****
bool __testinit = _M_is_indeterminate();
bool __testin = _M_mode & ios_base::in;
streamsize __retval = 0;
if (__testinit)
{
char_type __c = *__s++;
char_type __overfc = this->overflow(__c);
if (__c == __overfc)
! ++__retval;
}
if (_M_out_cur + __n < _M_out_end)
--- 455,468 ----
bool __testinit = _M_is_indeterminate();
bool __testin = _M_mode & ios_base::in;
streamsize __retval = 0;
+ streamsize __already = 0;
if (__testinit)
{
char_type __c = *__s++;
char_type __overfc = this->overflow(__c);
if (__c == __overfc)
! ++__already;
}
if (_M_out_cur + __n < _M_out_end)
*************** namespace std
*** 471,477 ****
if (_M_out_cur && _M_out_cur < _M_out_end)
{
! for (int __i = 0; __i < __retval; ++__i)
{
*_M_out_cur = *__s;
++__s;
--- 472,478 ----
if (_M_out_cur && _M_out_cur < _M_out_end)
{
! for (streamsize __i = __already; __i < __retval; ++__i)
{
*_M_out_cur = *__s;
++__s;
Index: ostream.tcc
===================================================================
RCS file: /cvs/libstdc++/libstdc++/bits/ostream.tcc,v
retrieving revision 1.16
diff -c -3 -p -r1.16 ostream.tcc
*** ostream.tcc 1999/05/21 10:33:16 1.16
--- ostream.tcc 1999/06/04 02:35:06
*************** namespace std {
*** 231,237 ****
throw;
}
! if (_M_fnumput->put(*this, *this, this->fill(), __buf).failed())
this->setstate(ios_base::failbit);
}
else
--- 231,238 ----
throw;
}
! streamsize __put = this->rdbuf()->sputn(__buf, __num);
! if ( __put != __num)
this->setstate(ios_base::failbit);
}
else