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 <bur...@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 <bur...@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