This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Patch, Fortran] PR57633 - Fix EOL handling with \r in list-directed I/O


gfortran failed to correctly read the file
   line1,1,
   line2
with DOS (\r\n) line endings. As the code already set EOL for "\r", finish_list_read didn't call eat_line. Result: The attempt to read "line2" actually accessed the last byte of line one, namely "\n", which it regarded as zero-sized string.

That's fixed by the patch to next_char.

eat_separator is a separate issue and unrelated to the PR. I also failed to create a test case for it. In any case, I regard the following as wrong:

     case '\r':
      dtp->u.p.at_eol = 1;
...
       if (n != '\n')
        {
          unget_char (dtp, n);
          break;

As the code explicitly does not regard "\r" as EOL in this case, I believe EOL shouldn't be set here.

(Recall, Unix (MacOS X, Linux, ...) have '\n' while DOS/Windows has "\r\n". While '\r' as line break exists (old Macs, pre MacOS X), gfortran does not support formatted I/O with "\r" record markers.)


Build and regtested on x86-64-gnu-linux.
OK for the trunk?

Tobias
2013-06-20  Tobias Burnus  <burnus@net-b.de>

	PR fortran/57633
	* io/list_read.c (next_char, eat_separator): Don't set EOL for \r.

2013-06-20  Tobias Burnus  <burnus@net-b.de>

	PR fortran/57633
	* gfortran.dg/list_read_11.f90: New.

diff --git a/libgfortran/io/list_read.c b/libgfortran/io/list_read.c
index c8a1bdfc..82a98a5 100644
--- a/libgfortran/io/list_read.c
+++ b/libgfortran/io/list_read.c
@@ -235,21 +235,21 @@ next_char (st_parameter_dt *dtp)
 	    }
 	}
     }
   else
     {
       c = fbuf_getc (dtp->u.p.current_unit);
       if (c != EOF && is_stream_io (dtp))
 	dtp->u.p.current_unit->strm_pos++;
     }
 done:
-  dtp->u.p.at_eol = (c == '\n' || c == '\r' || c == EOF);
+  dtp->u.p.at_eol = (c == '\n' || c == EOF);
   return c;
 }
 
 
 /* Push a character back onto the input.  */
 
 static void
 unget_char (st_parameter_dt *dtp, int c)
 {
   dtp->u.p.last_char = c;
@@ -327,21 +327,20 @@ eat_separator (st_parameter_dt *dtp)
     case ';':
       dtp->u.p.comma_flag = 1;
       eat_spaces (dtp);
       break;
 
     case '/':
       dtp->u.p.input_complete = 1;
       break;
 
     case '\r':
-      dtp->u.p.at_eol = 1;
       if ((n = next_char(dtp)) == EOF)
 	return LIBERROR_END;
       if (n != '\n')
 	{
 	  unget_char (dtp, n);
 	  break;
 	}
     /* Fall through.  */
     case '\n':
       dtp->u.p.at_eol = 1;
--- /dev/null	2013-06-20 10:08:42.876937873 +0200
+++ gcc/gcc/testsuite/gfortran.dg/list_read_11.f90	2013-06-20 10:55:13.329549458 +0200
@@ -0,0 +1,38 @@
+! { dg-do run }
+! { dg-options "-fbackslash" }
+!
+! PR fortran/57633
+!
+program teststuff
+  implicit none
+  integer::a
+  character(len=10)::s1,s2
+
+  open(11,file="testcase.txt",form='unformatted',access='stream',status='new')
+  write(11) 'line1,1,\r\nline2'
+  close(11)
+
+  open(11,file="testcase.txt",form='formatted')
+  s1 = repeat('x', len(s1))
+  a = 99
+  read(11,*)s1,a
+  if (s1 /= "line1" .or. a /= 1) call abort()
+
+  s1 = repeat('x', len(s1))
+  read(11,"(a)")s1
+  close(11,status="delete")
+  if (s1 /= "line2") call abort()
+
+
+  open(11,file="testcase.txt",form='unformatted',access='stream',status='new')
+  write(11) 'word1\rword2,\n'
+  close(11)
+
+  open(11,file="testcase.txt",form='formatted')
+  s1 = repeat('x', len(s1))
+  s2 = repeat('x', len(s1))
+  read(11,*)s1,s2
+  close(11,status="delete")
+  if (s1 /= "word1") call abort()
+  if (s2 /= "word2") call abort()
+end program teststuff

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