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]

[libgfortran] Correct handling of CRLF as line terminator


Attached patch makes libgfortran correctly handle CRLF as line
terminator (support until now was incomplete), for both reading (the
library can read both CRLF and LF files) and writing (the library will
write LF or CRLF as line terminators, depending on the value of
HAVE_CRLF when the compiler is built).

The patch to unix.c makes it possible to define HAVE_CRLF manually on
systems that don't have O_BINARY. We can thus run the testsuite using
CRLF on a non-CRLF system, and it opens the possibility of using a
compile-time option for line terminators instead of having this built
in the compiler. All the other files are the patch to handle reading
and writing of CRLF.

Regtested on i686-linux, with and without HAVE_CRLF. Introduces no
regression without it (the usual linux config) and fixes all testsuite
failures that existed on CRLF systems.

OK for 4.1 and mainline?

FX

:ADDPATCH libgfortran:

Attachment: crlf.ChangeLog
Description: Binary data

Index: libgfortran/io/list_read.c
===================================================================
--- libgfortran/io/list_read.c	(revision 107406)
+++ libgfortran/io/list_read.c	(working copy)
@@ -201,7 +201,7 @@
 static void
 eat_separator (st_parameter_dt *dtp)
 {
-  char c;
+  char c, n;
 
   eat_spaces (dtp);
   dtp->u.p.comma_flag = 0;
@@ -218,8 +218,18 @@
       dtp->u.p.input_complete = 1;
       break;
 
+    case '\r':
+      n = next_char(dtp);
+      if (n == '\n')
+	dtp->u.p.at_eol = 1;
+      else
+        {
+	  unget_char (dtp, n);
+	  unget_char (dtp, c);
+        } 
+      break;
+
     case '\n':
-    case '\r':
       dtp->u.p.at_eol = 1;
       break;
 
@@ -263,7 +273,7 @@
       else
 	{
 	  c = eat_spaces (dtp);
-	  if (c == '\n')
+	  if (c == '\n' || c == '\r')
 	    goto restart;
 	}
 
@@ -796,7 +806,7 @@
 	      goto done;
 	    }
 
-	  if (c != '\n')
+	  if (c != '\n' && c != '\r')
 	    push_char (dtp, c);
 	  break;
 
@@ -1749,32 +1759,56 @@
 	  /* "&namelist_name\n"  */
 
 	  len = dtp->namelist_name_len;
+#ifdef HAVE_CRLF
+	  p = write_block (dtp, len + 3);
+#else
 	  p = write_block (dtp, len + 2);
+#endif
 	  if (!p)
 	    goto query_return;
 	  memcpy (p, "&", 1);
 	  memcpy ((char*)(p + 1), dtp->namelist_name, len);
+#ifdef HAVE_CRLF
+	  memcpy ((char*)(p + len + 1), "\r\n", 2);
+#else
 	  memcpy ((char*)(p + len + 1), "\n", 1);
+#endif
 	  for (nl = dtp->u.p.ionml; nl; nl = nl->next)
 	    {
 
 	      /* " var_name\n"  */
 
 	      len = strlen (nl->var_name);
+#ifdef HAVE_CRLF
+	      p = write_block (dtp, len + 3);
+#else
 	      p = write_block (dtp, len + 2);
+#endif
 	      if (!p)
 		goto query_return;
 	      memcpy (p, " ", 1);
 	      memcpy ((char*)(p + 1), nl->var_name, len);
+#ifdef HAVE_CRLF
+	      memcpy ((char*)(p + len + 1), "\r\n", 2);
+#else
 	      memcpy ((char*)(p + len + 1), "\n", 1);
+#endif
 	    }
 
 	  /* "&end\n"  */
 
+#ifdef HAVE_CRLF
+	  p = write_block (dtp, 6);
+#else
 	  p = write_block (dtp, 5);
+#endif
 	  if (!p)
 	    goto query_return;
+#ifdef HAVE_CRLF
+	  memcpy (p, "&end\r\n", 6);
+#else
 	  memcpy (p, "&end\n", 5);
+#endif
 	}
 
       /* Flush the stream to force immediate output.  */
Index: libgfortran/io/io.h
===================================================================
--- libgfortran/io/io.h	(revision 107406)
+++ libgfortran/io/io.h	(working copy)
@@ -383,6 +383,10 @@
 	  char reversion_flag; /* Format reversion has occurred.  */
 	  char first_item;
 	  char seen_dollar;
+	  /* Whether an EOR condition was encountered. Value is:
+	       0 if no EOR was encountered
+	       1 if an EOR was encountered due to a 1-byte marker (LF)
+	       2 if an EOR was encountered due to a 2-bytes marker (CRLF) */
 	  char sf_seen_eor;
 	  char eor_condition;
 	  char no_leading_blank;
Index: libgfortran/io/unix.c
===================================================================
--- libgfortran/io/unix.c	(revision 107406)
+++ libgfortran/io/unix.c	(working copy)
@@ -1037,7 +1037,7 @@
 
   if (mktemp (template))
     do
-#ifdef HAVE_CRLF
+#if defined(HAVE_CRLF) && defined(O_BINARY)
       fd = open (template, O_RDWR | O_CREAT | O_EXCL | O_BINARY,
                  S_IREAD | S_IWRITE);
 #else
@@ -1127,7 +1127,7 @@
 
   /* rwflag |= O_LARGEFILE; */
 
-#ifdef HAVE_CRLF
+#if defined(HAVE_CRLF) && defined(O_BINARY)
   crflag |= O_BINARY;
 #endif
 
@@ -1475,7 +1475,7 @@
 }
 
 
-/* stream_at_eof()-- Returns nonzero if the stream is at the beginning
+/* stream_at_eof()-- Returns nonzero if the stream is at the end
  * of the file. */
 
 int
Index: libgfortran/io/transfer.c
===================================================================
--- libgfortran/io/transfer.c	(revision 107406)
+++ libgfortran/io/transfer.c	(working copy)
@@ -136,7 +136,8 @@
 read_sf (st_parameter_dt *dtp, int *length)
 {
   char *base, *p, *q;
-  int n, readlen;
+  int n, readlen, crlf;
+  gfc_offset pos;
 
   if (*length > SCRATCH_SIZE)
     dtp->u.p.line_buffer = get_mem (*length);
@@ -183,6 +184,19 @@
 	  if (dtp->u.p.advance_status == ADVANCE_NO || dtp->u.p.seen_dollar)
 	    dtp->u.p.eor_condition = 1;
 
+	  crlf = 0;
+	  /* If we encounter a CR, it might be a CRLF.  */
+	  if (*q == '\r') /* Probably a CRLF */
+	    {
+	      readlen = 1;
+	      pos = stream_offset (dtp->u.p.current_unit->s);
+	      q = salloc_r (dtp->u.p.current_unit->s, &readlen);
+	      if (*q != '\n' && readlen == 1) /* Not a CRLF after all.  */
+		sseek (dtp->u.p.current_unit->s, pos);
+	      else
+		crlf = 1;
+	    }
+
 	  /* Without padding, terminate the I/O statement without assigning
 	     the value.  With padding, the value still needs to be assigned,
 	     so we can just continue with a short read.  */
@@ -193,7 +207,7 @@
 	    }
 
 	  *length = n;
-	  dtp->u.p.sf_seen_eor = 1;
+	  dtp->u.p.sf_seen_eor = (crlf ? 2 : 1);
 	  break;
 	}
 
@@ -803,10 +817,20 @@
 	      /* Adjust everything for end-of-record condition */
 	      if (dtp->u.p.sf_seen_eor && !is_internal_unit (dtp))
 		{
-		  dtp->u.p.current_unit->bytes_left--;
+		  if (dtp->u.p.sf_seen_eor == 2)
+		    {
+		      /* The EOR was a CRLF (two bytes wide).  */
+		      dtp->u.p.current_unit->bytes_left -= 2;
+		      dtp->u.p.skips -= 2;
+		    }
+		  else
+		    {
+		      /* The EOR marker was only one byte wide.  */
+		      dtp->u.p.current_unit->bytes_left--;
+		      dtp->u.p.skips--;
+		    }
 		  bytes_used = pos;
 		  dtp->u.p.sf_seen_eor = 0;
-		  dtp->u.p.skips--;
 		}
 	      if (dtp->u.p.skips < 0)
 		{
Index: libgfortran/io/write.c
===================================================================
--- libgfortran/io/write.c	(revision 107406)
+++ libgfortran/io/write.c	(working copy)
@@ -1536,7 +1536,11 @@
 
   if (obj->type != GFC_DTYPE_DERIVED)
     {
+#ifdef HAVE_CRLF
+      write_character (dtp, "\r\n ", 3);
+#else
       write_character (dtp, "\n ", 2);
+#endif
       len = 0;
       if (base)
 	{
@@ -1728,7 +1732,11 @@
 	  if (num > 5)
 	    {
 	      num = 0;
+#ifdef HAVE_CRLF
+	      write_character (dtp, "\r\n ", 3);
+#else
 	      write_character (dtp, "\n ", 2);
+#endif
 	    }
 	  rep_ctr = 1;
 	}
@@ -1808,7 +1816,11 @@
 	  t1 = nml_write_obj (dtp, t2, dummy_offset, dummy, dummy_name);
 	}
     }
+#ifdef HAVE_CRLF
+  write_character (dtp, "  /\r\n ", 5);
+#else
   write_character (dtp, "  /\n", 4);
+#endif
 
   /* Recover the original delimiter.  */
 
Index: gcc/testsuite/gfortran.dg/ftell_2.f90
===================================================================
--- gcc/testsuite/gfortran.dg/ftell_2.f90	(revision 107406)
+++ gcc/testsuite/gfortran.dg/ftell_2.f90	(working copy)
@@ -1,8 +1,12 @@
 ! { dg-do run }
+  integer*8 o
   open (10, status="scratch")
   if (ftell(10) /= 0) call abort
   write (10,"(A)") "1234567"
-  if (ftell(10) /= 8) call abort
+  if (ftell(10) /= 8 .and. ftell(10) /= 9) call abort
+  o = ftell(10)
+  write (10,"(A)") "1234567"
+  if (ftell(10) /= 2 * o) call abort
   close (10)
   if (ftell(10) /= -1) call abort
   end
Index: gcc/testsuite/gfortran.dg/ftell_1.f90
===================================================================
--- gcc/testsuite/gfortran.dg/ftell_1.f90	(revision 107406)
+++ gcc/testsuite/gfortran.dg/ftell_1.f90	(working copy)
@@ -1,12 +1,15 @@
 ! { dg-do run }
-  integer*8 o
+  integer*8 o, o2
 
   open (10, status="scratch")
   call ftell (10, o)
   if (o /= 0) call abort
   write (10,"(A)") "1234567"
   call ftell (10, o)
-  if (o /= 8) call abort
+  if (o /= 8 .and. o /= 9) call abort
+  write (10,"(A)") "1234567"
+  call ftell (10, o2)
+  if (o2 /= 2 * o) call abort
   close (10)
   call ftell (10, o)
   if (o /= -1) call abort









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