[prev in list] [next in list] [prev in thread] [next in thread] 

List:       gcc
Subject:    Re: getline() doesn't seem to work?
From:       Per Bothner <bothner () cygnus ! com>
Date:       1998-01-31 3:39:59
[Download RAW message or body]

> > I don't know if this is a bug in getline, or just a bug in my
> > understanding of getline.  When I have the following program just
> > reading from my terminal, I have to hit control-D twice before the
> > loop exits.  It appears that the first time I hit control-D, getline

> How is this patch?
> Fri Jan 30 07:47:57 1998  H.J. Lu  (hjl@gnu.org)
>	* isgetline.cc (istream::getline, istream::get): Call
>	* isgetline.cc (istream::getline, istream::get): Call
>	streambuf::in_avail () to check EOF when _IO_getline ()
>	returns 0.

This is wrong.  istream::getline should not call streambuf::in_avail.
istream::getline should just be a more convienient and efficient
interface than you could write yourself as a loop using sgetc/sbumpc.
It should not require the more magic streambuf::in_avail.

Furthermore, this solution is not consistent.  fgets and gets do not
check for availability.  Instead they check if fp->_IO_file_flags
has _IO_ERR_SEEN set.  istream::getline should work similarly,
except use _IO_EOF_SEEN.

I thought about changing the interface of _IO_getline so it returns
-1 on EOF.  (The return type should then be changed from _IO_size_t
to _IO_ssize_t.)  That would make it easy to test if EOF was seen.
However, that would not solve the problem of a partial line line
followed by EOF (and no delimiter).  The code would still try to read
the delimiter - even after EOF is seen.   While this is presumably
harmless except on terminals, and a terminal would not return
a partial line followed by EOF - still, we should avoid reading an
extra character after EOF has been seen.  So I propose something like
the following.  (Note I have not looked at istream::get.)

Fri Jan 30 19:36:24 1998  Per Bothner  <bothner@cygnus.com>

	*  isgetline.c (istream::getline):  Don't try to sbumpc
	if _IO_getline returned 0 chars, and we have seen EOF.

Index: isgetline.cc
===================================================================
RCS file: /cvs/cvsfiles/devo/libio/isgetline.cc,v
retrieving revision 1.7
diff -u -r1.7 isgetline.cc
--- isgetline.cc	1995/11/06 23:06:45	1.7
+++ isgetline.cc	1998/01/31 03:34:08
@@ -34,22 +34,25 @@
       set(ios::failbit);
       return *this;
     }
-  int ch;
+  int ch = EOF;
   if (ipfx1())
     {
       streambuf *sb = rdbuf();
       _gcount = _IO_getline(sb, buf, len - 1, delim, -1);
-      ch = sb->sbumpc();
-      if (ch == EOF)
-	set (_gcount == 0 ? (ios::failbit|ios::eofbit) : ios::eofbit);
-      else if (ch != (unsigned char) delim)
+      if (_gcount == 0 && (sb->_IO_file_flags & _IO_EOF_SEEN))
+	set (ios::eofbit);
+      else
 	{
-	  set(ios::failbit);
-	  sb->sungetc(); // Leave delimiter unread.
+	  ch = sb->sbumpc();
+	  if (ch == EOF)
+	    set (ios::failbit|ios::eofbit);
+	  else if (ch != (unsigned char) delim)
+	    {
+	      set(ios::failbit);
+	      sb->sungetc(); // Leave delimiter unread.
+	    }
 	}
     }
-  else
-    ch = EOF;
   buf[_gcount] = '\0';
   if (ch == (unsigned char)delim)
     _gcount++; // The delimiter is counted in the gcount().

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic