]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
backport: re PR fortran/58324 (Bogus END-of-line error with list-directed I/O of...
authorJerry DeLisle <jvdelisle@gcc.gnu.org>
Sat, 15 Mar 2014 20:31:33 +0000 (20:31 +0000)
committerJerry DeLisle <jvdelisle@gcc.gnu.org>
Sat, 15 Mar 2014 20:31:33 +0000 (20:31 +0000)
2014-03-15  Jerry DeLisle  <jvdelisle@gcc.gnu>

Backport from mainline
PR libfortran/58324
PR libfortran/38199
* io/list_read.c (finish_list_read): Read one character to check
for the end of the file.  If it is the end, then issue the file
end error message.  If not, use eat_line to reach the end
without giving error.  The next attempt to read will then
issue the error as described above.
* io/read.c (read_decimal): Quickly skip spaces to avoid calls
to next_char.
* io/unit.c (is_trim_ok): New helper function to check various
conditions to see if its OK to trim the internal unit string.
(get_internal_unit): Use LEN_TRIM to shorten selected internal
unit strings for optimizing READ. Enable this optimization for
formatted READ.

From-SVN: r208595

libgfortran/ChangeLog
libgfortran/io/list_read.c
libgfortran/io/read.c
libgfortran/io/unit.c

index fa07295f6ed488372e4b7a16065e9b4ece1a7e35..73336977d7ac38e706e836009795b84bdb7bdc26 100644 (file)
@@ -1,3 +1,21 @@
+2014-03-15  Jerry DeLisle  <jvdelisle@gcc.gnu>
+
+       Backport from mainline
+       PR libfortran/58324
+       PR libfortran/38199
+       * io/list_read.c (finish_list_read): Read one character to check
+       for the end of the file.  If it is the end, then issue the file
+       end error message.  If not, use eat_line to reach the end
+       without giving error.  The next attempt to read will then
+       issue the error as described above.
+       * io/read.c (read_decimal): Quickly skip spaces to avoid calls
+       to next_char.
+       * io/unit.c (is_trim_ok): New helper function to check various
+       conditions to see if its OK to trim the internal unit string.
+       (get_internal_unit): Use LEN_TRIM to shorten selected internal
+       unit strings for optimizing READ. Enable this optimization for
+       formatted READ.
+
 2014-02-21  Jerry DeLisle  <jvdelisle@gcc.gnu>
            Dominique d'Humieres  <dominiq@lps.ens.fr>
            Steven G. Kargl  <kargl@gcc.gnu.org>
index 7cafad0c55d551c7efd224832904a63df3848bfe..91ef8b5c8643ac69774c3a403b17903a80297da4 100644 (file)
@@ -2034,8 +2034,6 @@ list_formatted_read (st_parameter_dt *dtp, bt type, void *p, int kind,
 void
 finish_list_read (st_parameter_dt *dtp)
 {
-  int err;
-
   free_saved (dtp);
 
   fbuf_flush (dtp->u.p.current_unit, dtp->u.p.mode);
@@ -2046,12 +2044,22 @@ finish_list_read (st_parameter_dt *dtp)
       return;
     }
 
-  err = eat_line (dtp);
-  if (err == LIBERROR_END)
+  if (!is_internal_unit (dtp))
     {
-      free_line (dtp);
-      hit_eof (dtp);
+      int c;
+      c = next_char (dtp);
+      if (c == EOF)
+       {
+         free_line (dtp);
+         hit_eof (dtp);
+         return;
+       }
+      if (c != '\n')
+       eat_line (dtp);
     }
+
+  free_line (dtp);
+
 }
 
 /*                     NAMELIST INPUT
index 2da1048f8ae8d1504a1b601e24b37dc49a307d85..f45e1b4edfefc5064bd4fc0b24073590cefd6023 100644 (file)
@@ -655,7 +655,13 @@ read_decimal (st_parameter_dt *dtp, const fnode *f, char *dest, int length)
        
       if (c == ' ')
         {
-         if (dtp->u.p.blank_status == BLANK_NULL) continue;
+         if (dtp->u.p.blank_status == BLANK_NULL)
+           {
+             /* Skip spaces.  */
+             for ( ; w > 0; p++, w--)
+               if (*p != ' ') break; 
+             continue;
+           }
          if (dtp->u.p.blank_status == BLANK_ZERO) c = '0';
         }
         
index f8c1516e0c78a4b84e3a1ce60e71034fe66ecb10..ab61769a2eb16b006e25432a0415c16f3fe0f007 100644 (file)
@@ -29,6 +29,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 #include "unix.h"
 #include <stdlib.h>
 #include <string.h>
+#include <stdbool.h>
 
 
 /* IO locking rules:
@@ -375,6 +376,38 @@ find_or_create_unit (int n)
 }
 
 
+/* Helper function to check rank, stride, format string, and namelist.
+   This is used for optimization. You can't trim out blanks or shorten
+   the string if trailing spaces are significant.  */
+static bool
+is_trim_ok (st_parameter_dt *dtp)
+{
+  /* Check rank and stride.  */
+  if (dtp->internal_unit_desc
+      && (GFC_DESCRIPTOR_RANK (dtp->internal_unit_desc) > 1
+         || GFC_DESCRIPTOR_STRIDE(dtp->internal_unit_desc, 0) != 1))
+    return false;
+  /* Format strings can not have 'BZ' or '/'.  */
+  if (dtp->common.flags & IOPARM_DT_HAS_FORMAT)
+    {
+      char *p = dtp->format;
+      off_t i;
+      if (dtp->common.flags & IOPARM_DT_HAS_BLANK)
+       return false;
+      for (i = 0; i < dtp->format_len; i++)
+       {
+         if (p[i] == '/') return false;
+         if (p[i] == 'b' || p[i] == 'B')
+           if (p[i+1] == 'z' || p[i+1] == 'Z')
+             return false;
+       }
+    }
+  if (dtp->u.p.ionml) /* A namelist.  */
+    return false;
+  return true;
+}
+
+
 gfc_unit *
 get_internal_unit (st_parameter_dt *dtp)
 {
@@ -402,6 +435,22 @@ get_internal_unit (st_parameter_dt *dtp)
      some other file I/O unit.  */
   iunit->unit_number = -1;
 
+  /* As an optimization, adjust the unit record length to not
+     include trailing blanks. This will not work under certain conditions
+     where trailing blanks have significance.  */
+  if (dtp->u.p.mode == READING && is_trim_ok (dtp))
+    {
+      int len;
+      if (dtp->common.unit == 0)
+         len = string_len_trim (dtp->internal_unit_len,
+                                                  dtp->internal_unit);
+      else
+         len = string_len_trim_char4 (dtp->internal_unit_len,
+                             (const gfc_char4_t*) dtp->internal_unit);
+      dtp->internal_unit_len = len; 
+      iunit->recl = dtp->internal_unit_len;
+    }
+
   /* Set up the looping specification from the array descriptor, if any.  */
 
   if (is_array_io (dtp))
@@ -414,27 +463,6 @@ get_internal_unit (st_parameter_dt *dtp)
 
       start_record *= iunit->recl;
     }
-  else
-    {
-      /* If we are not processing an array, adjust the unit record length not
-        to include trailing blanks for list-formatted reads.  */
-      if (dtp->u.p.mode == READING && !(dtp->common.flags & IOPARM_DT_HAS_FORMAT))
-       {
-         if (dtp->common.unit == 0)
-           {
-             dtp->internal_unit_len =
-               string_len_trim (dtp->internal_unit_len, dtp->internal_unit);
-             iunit->recl = dtp->internal_unit_len;
-           }
-         else
-           {
-             dtp->internal_unit_len =
-               string_len_trim_char4 (dtp->internal_unit_len,
-                                      (const gfc_char4_t*) dtp->internal_unit);
-             iunit->recl = dtp->internal_unit_len;
-           }
-       }
-    }
 
   /* Set initial values for unit parameters.  */
   if (dtp->common.unit)