This is the mail archive of the libstdc++@sourceware.cygnus.com mailing list for the libstdc++ project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

[patch] bits/istream.tcc - getline(char_type*,streamsize,char_type)


I ran across a bug with ifstream::getline(...). Basically, when reading
a partial line with n as max readlength, n-2 chars will be stored if 
char n-1 is the delimiter. The following patch corrects this. The
testsuite can be used to verify the new behavior, as prescribed by
27.6.1.3 of the std.

cheers.
-- 
Damon Brent Verner
Cracker JackŪ Certified Professional
brent@rcfile.org, brent@linux1.org
Index: istream.tcc
===================================================================
RCS file: /cvs/gcc/egcs/libstdc++-v3/bits/istream.tcc,v
retrieving revision 1.1
diff -c -p -3 -r1.1 istream.tcc
*** istream.tcc	2000/04/21 20:33:28	1.1
--- istream.tcc	2000/07/01 11:51:36
*************** namespace std {
*** 627,656 ****
        if (__cerb) 
  	{
  	  try {
- 	    int_type __idelim = traits_type::to_int_type(__delim);
  	    __streambuf_type* __sb = this->rdbuf();
! 	    int_type __c = __sb->sbumpc();
  	    const int_type __eof = traits_type::eof();
  	    bool __testdelim = __c == __idelim;
  	    bool __testeof =  __c == __eof;
! 	    
! 	    while (_M_gcount < __n - 1 && !__testeof && !__testdelim)
! 	      {
  		*__s++ = traits_type::to_char_type(__c);
- 		++_M_gcount;
  		__c = __sb->sbumpc();
  		__testeof = __c == __eof;
  		__testdelim = __c == __idelim;
! 	      }
! 	    if (_M_gcount == __n - 1 && !__testeof && !__testdelim)
! 	      {
  		__sb->sputbackc(traits_type::to_char_type(__c));
  		this->setstate(ios_base::failbit);
- 	      }	    
- 	    if (__testdelim)
- 	      ++_M_gcount;
- 	    if (__testeof)
- 	      this->setstate(ios_base::eofbit);
  	  }
  	  catch(exception& __fail){
  	    // 27.6.1.3 paragraph 1
--- 627,656 ----
        if (__cerb) 
  	{
  	  try {
  	    __streambuf_type* __sb = this->rdbuf();
! 	    const int_type __idelim = traits_type::to_int_type(__delim);
  	    const int_type __eof = traits_type::eof();
+ 	    int_type __c = __sb->sbumpc();
  	    bool __testdelim = __c == __idelim;
  	    bool __testeof =  __c == __eof;
! 
! 	    while (!__testeof && ++_M_gcount < __n && !__testdelim){
  		*__s++ = traits_type::to_char_type(__c);
  		__c = __sb->sbumpc();
  		__testeof = __c == __eof;
  		__testdelim = __c == __idelim;
! 	    }
! 
! 	    if(__testeof){
! 		this->setstate(ios_base::eofbit);
! 	    }
! 	    else if(!__testdelim){
! 		--_M_gcount;
  		__sb->sputbackc(traits_type::to_char_type(__c));
+ 		this->setstate(ios_base::failbit);
+ 	    }
+ 	    if(!_M_gcount)
  		this->setstate(ios_base::failbit);
  	  }
  	  catch(exception& __fail){
  	    // 27.6.1.3 paragraph 1
*************** namespace std {
*** 661,668 ****
  	  }
  	}
        *__s = char_type(NULL);
-       if (!_M_gcount || _M_gcount == __n - 1)
- 	this->setstate(ios_base::failbit);
        return *this;
      }
    
--- 661,666 ----
#include <cstring>
#include <istream>
#include <sstream>

// just because it speeds up debugging when you _know_
// __which__ test fails :)
#ifdef DEBUG_ASSERT
#include <cassert>
#  define VERIFY(fn) assert(fn)
#else
#  define VERIFY(fn)
#endif

int
main()
{

  const char* charray = "
a
aa
aaa
aaaa
aaaaa
aaaaaa
aaaaaaa
aaaaaaaa
aaaaaaaaa
aaaaaaaaaa
aaaaaaaaaaa
aaaaaaaaaaaa
aaaaaaaaaaaaa
aaaaaaaaaaaaaa
";

  const std::streamsize it = 5;
  std::streamsize br = 0;
  char tmp[it];
  std::stringbuf sb(charray, std::ios_base::in);
  std::istream ifs(&sb);
  std::streamsize blen = strlen(charray);
  VERIFY( ifs );
  while( ifs.getline(tmp,it) || ifs.gcount() ){
    br += ifs.gcount();
    if( ifs.eof() ){
      // just sanity checks to make sure we've
      // extracted the same number of chars that
      // were in the file.
      VERIFY( br == blen );
      // also, we should only set the failbit if
      // we could _extract_ no chars from the 
      // stream, i.e. the first read returned EOF
      VERIFY( ifs.fail() && ifs.gcount() == 0 );
    }
    else if( ifs.fail() ){
      // we've extracted 'it' chars from the stream
      // without finding the delimiter, but we only
      // store 'it - 1' chars and put the last read
      // char back into the stream. also, make sure
      // that eofbit is not getting set.
      VERIFY( ifs.gcount() == it - 1 );
      VERIFY( ifs.gcount() == (int)strlen(tmp) );
      ifs.clear(ifs.rdstate() & ~std::ios::failbit);
      VERIFY( ifs );
      continue;
    }
    else {
      // read a delimiter. make sure it was counted.
      // other stuff ???
      VERIFY( ifs.gcount() == (int)strlen(tmp) + 1 );
      continue;
    }
  }
  return 0;
}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]