OSDN Git Service

2009-08-02 Jerry DeLisle <jvdelisle@gcc.gnu.org>
[pf3gnuchains/gcc-fork.git] / libgfortran / io / list_read.c
index 939c4a1..bcc00e1 100644 (file)
@@ -1,39 +1,35 @@
-/* Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+/* Copyright (C) 2002, 2003, 2004, 2005, 2007, 2008, 2009
+   Free Software Foundation, Inc.
    Contributed by Andy Vaught
    Namelist input contributed by Paul Thomas
+   F2003 I/O support contributed by Jerry DeLisle
 
 This file is part of the GNU Fortran 95 runtime library (libgfortran).
 
 Libgfortran is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
 any later version.
 
-In addition to the permissions in the GNU General Public License, the
-Free Software Foundation gives you unlimited permission to link the
-compiled version of this file into combinations with other programs,
-and to distribute those combinations without any restriction coming
-from the use of this file.  (The General Public License restrictions
-do apply in other respects; for example, they cover modification of
-the file, and distribution when not linked into a combine
-executable.)
-
 Libgfortran is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
-You should have received a copy of the GNU General Public License
-along with Libgfortran; see the file COPYING.  If not, write to
-the Free Software Foundation, 51 Franklin Street, Fifth Floor,
-Boston, MA 02110-1301, USA.  */
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+<http://www.gnu.org/licenses/>.  */
 
 
-#include "config.h"
+#include "io.h"
 #include <string.h>
+#include <stdlib.h>
 #include <ctype.h>
-#include "libgfortran.h"
-#include "io.h"
 
 
 /* List directed input.  Several parsing subroutines are practically
@@ -54,17 +50,21 @@ Boston, MA 02110-1301, USA.  */
                       case '5': case '6': case '7': case '8': case '9'
 
 #define CASE_SEPARATORS  case ' ': case ',': case '/': case '\n': case '\t': \
-                         case '\r'
+                         case '\r': case ';'
 
 /* This macro assumes that we're operating on a variable.  */
 
 #define is_separator(c) (c == '/' ||  c == ',' || c == '\n' || c == ' ' \
-                         || c == '\t' || c == '\r')
+                         || c == '\t' || c == '\r' || c == ';')
 
 /* Maximum repeat count.  Less than ten times the maximum signed int32.  */
 
 #define MAX_REPEAT 200000000
 
+#ifndef HAVE_SNPRINTF
+# undef snprintf
+# define snprintf(str, size, ...) sprintf (str, __VA_ARGS__)
+#endif
 
 /* Save a character to a string buffer, enlarging it as necessary.  */
 
@@ -75,9 +75,8 @@ push_char (st_parameter_dt *dtp, char c)
 
   if (dtp->u.p.saved_string == NULL)
     {
-      if (dtp->u.p.scratch == NULL)
-       dtp->u.p.scratch = get_mem (SCRATCH_SIZE);
-      dtp->u.p.saved_string = dtp->u.p.scratch;
+      dtp->u.p.saved_string = get_mem (SCRATCH_SIZE);
+      // memset below should be commented out.
       memset (dtp->u.p.saved_string, 0, SCRATCH_SIZE);
       dtp->u.p.saved_length = SCRATCH_SIZE;
       dtp->u.p.saved_used = 0;
@@ -86,15 +85,15 @@ push_char (st_parameter_dt *dtp, char c)
   if (dtp->u.p.saved_used >= dtp->u.p.saved_length)
     {
       dtp->u.p.saved_length = 2 * dtp->u.p.saved_length;
-      new = get_mem (2 * dtp->u.p.saved_length);
-
-      memset (new, 0, 2 * dtp->u.p.saved_length);
-
-      memcpy (new, dtp->u.p.saved_string, dtp->u.p.saved_used);
-      if (dtp->u.p.saved_string != dtp->u.p.scratch)
-       free_mem (dtp->u.p.saved_string);
-
+      new = realloc (dtp->u.p.saved_string, dtp->u.p.saved_length);
+      if (new == NULL)
+       generate_error (&dtp->common, LIBERROR_OS, NULL);
       dtp->u.p.saved_string = new;
+      
+      // Also this should not be necessary.
+      memset (new + dtp->u.p.saved_used, 0, 
+             dtp->u.p.saved_length - dtp->u.p.saved_used);
+
     }
 
   dtp->u.p.saved_string[dtp->u.p.saved_used++] = c;
@@ -109,19 +108,36 @@ free_saved (st_parameter_dt *dtp)
   if (dtp->u.p.saved_string == NULL)
     return;
 
-  if (dtp->u.p.saved_string != dtp->u.p.scratch)
-    free_mem (dtp->u.p.saved_string);
+  free_mem (dtp->u.p.saved_string);
 
   dtp->u.p.saved_string = NULL;
   dtp->u.p.saved_used = 0;
 }
 
 
+/* Free the line buffer if necessary.  */
+
+static void
+free_line (st_parameter_dt *dtp)
+{
+  dtp->u.p.item_count = 0;
+  dtp->u.p.line_buffer_enabled = 0;
+
+  if (dtp->u.p.line_buffer == NULL)
+    return;
+
+  free_mem (dtp->u.p.line_buffer);
+  dtp->u.p.line_buffer = NULL;
+}
+
+
 static char
 next_char (st_parameter_dt *dtp)
 {
-  int length;
-  char c, *p;
+  ssize_t length;
+  gfc_offset record;
+  char c;
+  int cc;
 
   if (dtp->u.p.last_char != '\0')
     {
@@ -131,28 +147,105 @@ next_char (st_parameter_dt *dtp)
       goto done;
     }
 
-  length = 1;
+  /* Read from line_buffer if enabled.  */
 
-  p = salloc_r (dtp->u.p.current_unit->s, &length);
-  if (p == NULL)
+  if (dtp->u.p.line_buffer_enabled)
     {
-      generate_error (&dtp->common, ERROR_OS, NULL);
-      return '\0';
+      dtp->u.p.at_eol = 0;
+
+      c = dtp->u.p.line_buffer[dtp->u.p.item_count];
+      if (c != '\0' && dtp->u.p.item_count < 64)
+       {
+         dtp->u.p.line_buffer[dtp->u.p.item_count] = '\0';
+         dtp->u.p.item_count++;
+         goto done;
+       }
+
+      dtp->u.p.item_count = 0;
+      dtp->u.p.line_buffer_enabled = 0;
+    }    
+
+  /* Handle the end-of-record and end-of-file conditions for
+     internal array unit.  */
+  if (is_array_io (dtp))
+    {
+      if (dtp->u.p.at_eof)
+       longjmp (*dtp->u.p.eof_jump, 1);
+
+      /* Check for "end-of-record" condition.  */
+      if (dtp->u.p.current_unit->bytes_left == 0)
+       {
+         int finished;
+
+         c = '\n';
+         record = next_array_record (dtp, dtp->u.p.current_unit->ls,
+                                     &finished);
+
+         /* Check for "end-of-file" condition.  */      
+         if (finished)
+           {
+             dtp->u.p.at_eof = 1;
+             goto done;
+           }
+
+         record *= dtp->u.p.current_unit->recl;
+         if (sseek (dtp->u.p.current_unit->s, record, SEEK_SET) < 0)
+           longjmp (*dtp->u.p.eof_jump, 1);
+
+         dtp->u.p.current_unit->bytes_left = dtp->u.p.current_unit->recl;
+         goto done;
+       }
     }
 
-  if (length == 0)
+  /* Get the next character and handle end-of-record conditions.  */
+
+  if (is_internal_unit (dtp))
     {
-      /* For internal files return a newline instead of signalling EOF.  */
-      /* ??? This isn't quite right, but we don't handle internal files
-        with multiple records.  */
-      if (is_internal_unit (dtp))
-       c = '\n';
+      length = sread (dtp->u.p.current_unit->s, &c, 1);
+      if (length < 0)
+       {
+         generate_error (&dtp->common, LIBERROR_OS, NULL);
+         return '\0';
+       }
+  
+      if (is_array_io (dtp))
+       {
+         /* Check whether we hit EOF.  */ 
+         if (length == 0)
+           {
+             generate_error (&dtp->common, LIBERROR_INTERNAL_UNIT, NULL);
+             return '\0';
+           } 
+         dtp->u.p.current_unit->bytes_left--;
+       }
       else
-       longjmp (*dtp->u.p.eof_jump, 1);
+       {
+         if (dtp->u.p.at_eof) 
+           longjmp (*dtp->u.p.eof_jump, 1);
+         if (length == 0)
+           {
+             c = '\n';
+             dtp->u.p.at_eof = 1;
+           }
+       }
     }
   else
-    c = *p;
+    {
+      cc = fbuf_getc (dtp->u.p.current_unit);
+
+      if (cc == EOF)
+       {
+         if (dtp->u.p.current_unit->endfile == AT_ENDFILE)
+           longjmp (*dtp->u.p.eof_jump, 1);
+         dtp->u.p.current_unit->endfile = AT_ENDFILE;
+         c = '\n';
+       }
+      else
+       c = (char) cc;
+      if (is_stream_io (dtp) && cc != EOF)
+       dtp->u.p.current_unit->strm_pos++;
 
+    }
 done:
   dtp->u.p.at_eol = (c == '\n' || c == '\r');
   return c;
@@ -187,6 +280,20 @@ eat_spaces (st_parameter_dt *dtp)
 }
 
 
+/* This function reads characters through to the end of the current line and
+   just ignores them.  */
+
+static void
+eat_line (st_parameter_dt *dtp)
+{
+  char c;
+  if (!is_internal_unit (dtp))
+    do
+      c = next_char (dtp);
+    while (c != '\n');
+}
+
+
 /* Skip over a separator.  Technically, we don't always eat the whole
    separator.  This is because if we've processed the last input item,
    then a separator is unnecessary.  Plus the fact that operating
@@ -201,7 +308,7 @@ eat_spaces (st_parameter_dt *dtp)
 static void
 eat_separator (st_parameter_dt *dtp)
 {
-  char c;
+  char c, n;
 
   eat_spaces (dtp);
   dtp->u.p.comma_flag = 0;
@@ -210,6 +317,13 @@ eat_separator (st_parameter_dt *dtp)
   switch (c)
     {
     case ',':
+      if (dtp->u.p.current_unit->decimal_status == DECIMAL_COMMA)
+       {
+         unget_char (dtp, c);
+         break;
+       }
+      /* Fall through.  */
+    case ';':
       dtp->u.p.comma_flag = 1;
       eat_spaces (dtp);
       break;
@@ -218,9 +332,36 @@ eat_separator (st_parameter_dt *dtp)
       dtp->u.p.input_complete = 1;
       break;
 
-    case '\n':
     case '\r':
       dtp->u.p.at_eol = 1;
+      n = next_char(dtp);
+      if (n != '\n')
+       {
+         unget_char (dtp, n);
+         break;
+       }
+    /* Fall through.  */
+    case '\n':
+      dtp->u.p.at_eol = 1;
+      if (dtp->u.p.namelist_mode)
+       {
+         do
+           {
+             c = next_char (dtp);
+             if (c == '!')
+               {
+                 eat_line (dtp);
+                 c = next_char (dtp);
+                 if (c == '!')
+                   {
+                     eat_line (dtp);
+                     c = next_char (dtp);
+                   }
+               }
+           }
+         while (c == '\n' || c == '\r' || c == ' ' || c == '\t');
+         unget_char (dtp, c);
+       }
       break;
 
     case '!':
@@ -263,7 +404,7 @@ finish_separator (st_parameter_dt *dtp)
       else
        {
          c = eat_spaces (dtp);
-         if (c == '\n')
+         if (c == '\n' || c == '\r')
            goto restart;
        }
 
@@ -271,7 +412,8 @@ finish_separator (st_parameter_dt *dtp)
 
     case '/':
       dtp->u.p.input_complete = 1;
-      if (!dtp->u.p.namelist_mode) next_record (dtp, 0);
+      if (!dtp->u.p.namelist_mode)
+       return;
       break;
 
     case '\n':
@@ -294,6 +436,7 @@ finish_separator (st_parameter_dt *dtp)
     }
 }
 
+
 /* This function is needed to catch bad conversions so that namelist can
    attempt to see if dtp->u.p.saved_string contains a new object name rather
    than a bad value.  */
@@ -357,10 +500,10 @@ convert_integer (st_parameter_dt *dtp, int length, int negative)
 
       if (dtp->u.p.repeat_count == 0)
        {
-         st_sprintf (message, "Zero repeat count in item %d of list input",
-                     dtp->u.p.item_count);
+         sprintf (message, "Zero repeat count in item %d of list input",
+                  dtp->u.p.item_count);
 
-         generate_error (&dtp->common, ERROR_READ_VALUE, message);
+         generate_error (&dtp->common, LIBERROR_READ_VALUE, message);
          m = 1;
        }
     }
@@ -370,14 +513,14 @@ convert_integer (st_parameter_dt *dtp, int length, int negative)
 
  overflow:
   if (length == -1)
-    st_sprintf (message, "Repeat count overflow in item %d of list input",
-               dtp->u.p.item_count);
+    sprintf (message, "Repeat count overflow in item %d of list input",
+            dtp->u.p.item_count);
   else
-    st_sprintf (message, "Integer overflow while reading item %d",
-               dtp->u.p.item_count);
+    sprintf (message, "Integer overflow while reading item %d",
+            dtp->u.p.item_count);
 
   free_saved (dtp);
-  generate_error (&dtp->common, ERROR_READ_VALUE, message);
+  generate_error (&dtp->common, LIBERROR_READ_VALUE, message);
 
   return 1;
 }
@@ -420,11 +563,11 @@ parse_repeat (st_parameter_dt *dtp)
 
          if (repeat > MAX_REPEAT)
            {
-             st_sprintf (message,
-                         "Repeat count overflow in item %d of list input",
-                         dtp->u.p.item_count);
+             sprintf (message,
+                      "Repeat count overflow in item %d of list input",
+                      dtp->u.p.item_count);
 
-             generate_error (&dtp->common, ERROR_READ_VALUE, message);
+             generate_error (&dtp->common, LIBERROR_READ_VALUE, message);
              return 1;
            }
 
@@ -433,11 +576,11 @@ parse_repeat (st_parameter_dt *dtp)
        case '*':
          if (repeat == 0)
            {
-             st_sprintf (message,
-                         "Zero repeat count in item %d of list input",
-                         dtp->u.p.item_count);
+             sprintf (message,
+                      "Zero repeat count in item %d of list input",
+                      dtp->u.p.item_count);
 
-             generate_error (&dtp->common, ERROR_READ_VALUE, message);
+             generate_error (&dtp->common, LIBERROR_READ_VALUE, message);
              return 1;
            }
 
@@ -453,51 +596,82 @@ parse_repeat (st_parameter_dt *dtp)
   return 0;
 
  bad_repeat:
-  st_sprintf (message, "Bad repeat count in item %d of list input",
-             dtp->u.p.item_count);
 
-  generate_error (&dtp->common, ERROR_READ_VALUE, message);
+  eat_line (dtp);
+  free_saved (dtp);
+  sprintf (message, "Bad repeat count in item %d of list input",
+          dtp->u.p.item_count);
+  generate_error (&dtp->common, LIBERROR_READ_VALUE, message);
   return 1;
 }
 
 
+/* To read a logical we have to look ahead in the input stream to make sure
+    there is not an equal sign indicating a variable name.  To do this we use 
+    line_buffer to point to a temporary buffer, pushing characters there for
+    possible later reading. */
+
+static void
+l_push_char (st_parameter_dt *dtp, char c)
+{
+  if (dtp->u.p.line_buffer == NULL)
+    {
+      dtp->u.p.line_buffer = get_mem (SCRATCH_SIZE);
+      memset (dtp->u.p.line_buffer, 0, SCRATCH_SIZE);
+    }
+
+  dtp->u.p.line_buffer[dtp->u.p.item_count++] = c;
+}
+
+
 /* Read a logical character on the input.  */
 
 static void
 read_logical (st_parameter_dt *dtp, int length)
 {
   char c, message[100];
-  int v;
+  int i, v;
 
   if (parse_repeat (dtp))
     return;
 
-  c = next_char (dtp);
+  c = tolower (next_char (dtp));
+  l_push_char (dtp, c);
   switch (c)
     {
     case 't':
-    case 'T':
       v = 1;
+      c = next_char (dtp);
+      l_push_char (dtp, c);
+
+      if (!is_separator(c))
+       goto possible_name;
+
+      unget_char (dtp, c);
       break;
     case 'f':
-    case 'F':
       v = 0;
+      c = next_char (dtp);
+      l_push_char (dtp, c);
+
+      if (!is_separator(c))
+       goto possible_name;
+
+      unget_char (dtp, c);
       break;
 
     case '.':
-      c = next_char (dtp);
+      c = tolower (next_char (dtp));
       switch (c)
        {
-       case 't':
-       case 'T':
-         v = 1;
-         break;
-       case 'f':
-       case 'F':
-         v = 0;
-         break;
-       default:
-         goto bad_logical;
+         case 't':
+           v = 1;
+           break;
+         case 'f':
+           v = 0;
+           break;
+         default:
+           goto bad_logical;
        }
 
       break;
@@ -508,6 +682,9 @@ read_logical (st_parameter_dt *dtp, int length)
       return;                  /* Null value.  */
 
     default:
+      /* Save the character in case it is the beginning
+        of the next object name. */
+      unget_char (dtp, c);
       goto bad_logical;
     }
 
@@ -523,20 +700,64 @@ read_logical (st_parameter_dt *dtp, int length)
 
   unget_char (dtp, c);
   eat_separator (dtp);
-  free_saved (dtp);
   set_integer ((int *) dtp->u.p.value, v, length);
+  free_line (dtp);
 
   return;
 
+ possible_name:
+
+  for(i = 0; i < 63; i++)
+    {
+      c = next_char (dtp);
+      if (is_separator(c))
+       {
+         /* All done if this is not a namelist read.  */
+         if (!dtp->u.p.namelist_mode)
+           goto logical_done;
+
+         unget_char (dtp, c);
+         eat_separator (dtp);
+         c = next_char (dtp);
+         if (c != '=')
+           {
+             unget_char (dtp, c);
+             goto logical_done;
+           }
+       }
+      l_push_char (dtp, c);
+      if (c == '=')
+       {
+         dtp->u.p.nml_read_error = 1;
+         dtp->u.p.line_buffer_enabled = 1;
+         dtp->u.p.item_count = 0;
+         return;
+       }
+      
+    }
+
  bad_logical:
 
+  free_line (dtp);
+
   if (nml_bad_return (dtp, c))
     return;
 
-  st_sprintf (message, "Bad logical value while reading item %d",
+  eat_line (dtp);
+  free_saved (dtp);
+  sprintf (message, "Bad logical value while reading item %d",
              dtp->u.p.item_count);
+  generate_error (&dtp->common, LIBERROR_READ_VALUE, message);
+  return;
 
-  generate_error (&dtp->common, ERROR_READ_VALUE, message);
+ logical_done:
+
+  dtp->u.p.saved_type = BT_LOGICAL;
+  dtp->u.p.saved_length = length;
+  set_integer ((int *) dtp->u.p.value, v, length);
+  free_saved (dtp);
+  free_line (dtp);
 }
 
 
@@ -652,12 +873,12 @@ read_integer (st_parameter_dt *dtp, int length)
 
   if (nml_bad_return (dtp, c))
     return;
-
+  
+  eat_line (dtp);
   free_saved (dtp);
-
-  st_sprintf (message, "Bad integer for item %d in list input",
+  sprintf (message, "Bad integer for item %d in list input",
              dtp->u.p.item_count);
-  generate_error (&dtp->common, ERROR_READ_VALUE, message);
+  generate_error (&dtp->common, LIBERROR_READ_VALUE, message);
 
   return;
 
@@ -706,9 +927,10 @@ read_character (st_parameter_dt *dtp, int length __attribute__ ((unused)))
     default:
       if (dtp->u.p.namelist_mode)
        {
-         unget_char (dtp,c);
+         unget_char (dtp, c);
          return;
        }
+
       push_char (dtp, c);
       goto get_string;
     }
@@ -796,7 +1018,7 @@ read_character (st_parameter_dt *dtp, int length __attribute__ ((unused)))
              goto done;
            }
 
-         if (c != '\n')
+         if (c != '\n' && c != '\r')
            push_char (dtp, c);
          break;
 
@@ -810,18 +1032,19 @@ read_character (st_parameter_dt *dtp, int length __attribute__ ((unused)))
      invalid.  */
  done:
   c = next_char (dtp);
-  if (is_separator (c))
+  if (is_separator (c) || c == '!')
     {
       unget_char (dtp, c);
       eat_separator (dtp);
       dtp->u.p.saved_type = BT_CHARACTER;
+      free_line (dtp);
     }
   else
     {
       free_saved (dtp);
-      st_sprintf (message, "Invalid string input in item %d",
+      sprintf (message, "Invalid string input in item %d",
                  dtp->u.p.item_count);
-      generate_error (&dtp->common, ERROR_READ_VALUE, message);
+      generate_error (&dtp->common, LIBERROR_READ_VALUE, message);
     }
 }
 
@@ -842,8 +1065,16 @@ parse_real (st_parameter_dt *dtp, void *buffer, int length)
       c = next_char (dtp);
     }
 
+  if (c == ',' && dtp->u.p.current_unit->decimal_status == DECIMAL_COMMA)
+    c = '.';
+  
   if (!isdigit (c) && c != '.')
-    goto bad;
+    {
+      if (c == 'i' || c == 'I' || c == 'n' || c == 'N')
+       goto inf_nan;
+      else
+       goto bad;
+    }
 
   push_char (dtp, c);
 
@@ -852,6 +1083,8 @@ parse_real (st_parameter_dt *dtp, void *buffer, int length)
   for (;;)
     {
       c = next_char (dtp);
+      if (c == ',' && dtp->u.p.current_unit->decimal_status == DECIMAL_COMMA)
+       c = '.';
       switch (c)
        {
        CASE_DIGITS:
@@ -902,6 +1135,7 @@ parse_real (st_parameter_dt *dtp, void *buffer, int length)
  exp2:
   if (!isdigit (c))
     goto bad;
+
   push_char (dtp, c);
 
   for (;;)
@@ -931,11 +1165,51 @@ parse_real (st_parameter_dt *dtp, void *buffer, int length)
 
   return m;
 
+ inf_nan:
+  /* Match INF and Infinity.  */
+  if ((c == 'i' || c == 'I')
+      && ((c = next_char (dtp)) == 'n' || c == 'N')
+      && ((c = next_char (dtp)) == 'f' || c == 'F'))
+    {
+       c = next_char (dtp);
+       if ((c != 'i' && c != 'I')
+           || ((c == 'i' || c == 'I')
+               && ((c = next_char (dtp)) == 'n' || c == 'N')
+               && ((c = next_char (dtp)) == 'i' || c == 'I')
+               && ((c = next_char (dtp)) == 't' || c == 'T')
+               && ((c = next_char (dtp)) == 'y' || c == 'Y')
+               && (c = next_char (dtp))))
+         {
+            if (is_separator (c))
+              unget_char (dtp, c);
+            push_char (dtp, 'i');
+            push_char (dtp, 'n');
+            push_char (dtp, 'f');
+            goto done;
+         }
+    } /* Match NaN.  */
+  else if (((c = next_char (dtp)) == 'a' || c == 'A')
+          && ((c = next_char (dtp)) == 'n' || c == 'N')
+          && (c = next_char (dtp)))
+    {
+      if (is_separator (c))
+       unget_char (dtp, c);
+      push_char (dtp, 'n');
+      push_char (dtp, 'a');
+      push_char (dtp, 'n');
+      goto done;
+    }
+
  bad:
+
+  if (nml_bad_return (dtp, c))
+    return 0;
+
+  eat_line (dtp);
   free_saved (dtp);
-  st_sprintf (message, "Bad floating point number for item %d",
+  sprintf (message, "Bad floating point number for item %d",
              dtp->u.p.item_count);
-  generate_error (&dtp->common, ERROR_READ_VALUE, message);
+  generate_error (&dtp->common, LIBERROR_READ_VALUE, message);
 
   return 1;
 }
@@ -945,7 +1219,7 @@ parse_real (st_parameter_dt *dtp, void *buffer, int length)
    what it is right away.  */
 
 static void
-read_complex (st_parameter_dt *dtp, int kind, size_t size)
+read_complex (st_parameter_dt *dtp, void * dest, int kind, size_t size)
 {
   char message[100];
   char c;
@@ -969,7 +1243,7 @@ read_complex (st_parameter_dt *dtp, int kind, size_t size)
     }
 
   eat_spaces (dtp);
-  if (parse_real (dtp, dtp->u.p.value, kind))
+  if (parse_real (dtp, dest, kind))
     return;
 
 eol_1:
@@ -980,7 +1254,8 @@ eol_1:
   else
     unget_char (dtp, c);
 
-  if (next_char (dtp) != ',')
+  if (next_char (dtp)
+      !=  (dtp->u.p.current_unit->decimal_status == DECIMAL_POINT ? ',' : ';'))
     goto bad_complex;
 
 eol_2:
@@ -991,7 +1266,7 @@ eol_2:
   else
     unget_char (dtp, c);
 
-  if (parse_real (dtp, dtp->u.p.value + size / 2, kind))
+  if (parse_real (dtp, dest + size / 2, kind))
     return;
 
   eat_spaces (dtp);
@@ -1014,24 +1289,28 @@ eol_2:
   if (nml_bad_return (dtp, c))
     return;
 
-  st_sprintf (message, "Bad complex value in item %d of list input",
+  eat_line (dtp);
+  free_saved (dtp);
+  sprintf (message, "Bad complex value in item %d of list input",
              dtp->u.p.item_count);
-
-  generate_error (&dtp->common, ERROR_READ_VALUE, message);
+  generate_error (&dtp->common, LIBERROR_READ_VALUE, message);
 }
 
 
 /* Parse a real number with a possible repeat count.  */
 
 static void
-read_real (st_parameter_dt *dtp, int length)
+read_real (st_parameter_dt *dtp, void * dest, int length)
 {
   char c, message[100];
   int seen_dp;
+  int is_inf;
 
   seen_dp = 0;
 
   c = next_char (dtp);
+  if (c == ',' && dtp->u.p.current_unit->decimal_status == DECIMAL_COMMA)
+    c = '.';
   switch (c)
     {
     CASE_DIGITS:
@@ -1052,6 +1331,12 @@ read_real (st_parameter_dt *dtp, int length)
       eat_separator (dtp);
       return;
 
+    case 'i':
+    case 'I':
+    case 'n':
+    case 'N':
+      goto inf_nan;
+
     default:
       goto bad_real;
     }
@@ -1061,6 +1346,8 @@ read_real (st_parameter_dt *dtp, int length)
   for (;;)
     {
       c = next_char (dtp);
+      if (c == ',' && dtp->u.p.current_unit->decimal_status == DECIMAL_COMMA)
+       c = '.';
       switch (c)
        {
        CASE_DIGITS:
@@ -1068,8 +1355,8 @@ read_real (st_parameter_dt *dtp, int length)
          break;
 
        case '.':
-          if (seen_dp)
-            goto bad_real;
+         if (seen_dp)
+           goto bad_real;
 
          seen_dp = 1;
          push_char (dtp, c);
@@ -1093,7 +1380,7 @@ read_real (st_parameter_dt *dtp, int length)
          goto got_repeat;
 
        CASE_SEPARATORS:
-          if (c != '\n' &&  c != ',' && c != '\r')
+          if (c != '\n' && c != ',' && c != '\r' && c != ';')
            unget_char (dtp, c);
          goto done;
 
@@ -1125,8 +1412,16 @@ read_real (st_parameter_dt *dtp, int length)
       c = next_char (dtp);
     }
 
+  if (c == ',' && dtp->u.p.current_unit->decimal_status == DECIMAL_COMMA)
+    c = '.';
+
   if (!isdigit (c) && c != '.')
-    goto bad_real;
+    {
+      if (c == 'i' || c == 'I' || c == 'n' || c == 'N')
+       goto inf_nan;
+      else
+       goto bad_real;
+    }
 
   if (c == '.')
     {
@@ -1142,6 +1437,8 @@ read_real (st_parameter_dt *dtp, int length)
   for (;;)
     {
       c = next_char (dtp);
+      if (c == ',' && dtp->u.p.current_unit->decimal_status == DECIMAL_COMMA)
+       c = '.';
       switch (c)
        {
        CASE_DIGITS:
@@ -1216,22 +1513,122 @@ read_real (st_parameter_dt *dtp, int length)
   unget_char (dtp, c);
   eat_separator (dtp);
   push_char (dtp, '\0');
-  if (convert_real (dtp, dtp->u.p.value, dtp->u.p.saved_string, length))
+  if (convert_real (dtp, dest, dtp->u.p.saved_string, length))
     return;
 
   free_saved (dtp);
   dtp->u.p.saved_type = BT_REAL;
   return;
 
+ inf_nan:
+  l_push_char (dtp, c);
+  is_inf = 0;
+
+  /* Match INF and Infinity.  */
+  if (c == 'i' || c == 'I')
+    {
+      c = next_char (dtp);
+      l_push_char (dtp, c);
+      if (c != 'n' && c != 'N')
+       goto unwind;
+      c = next_char (dtp);
+      l_push_char (dtp, c);
+      if (c != 'f' && c != 'F')
+       goto unwind;
+      c = next_char (dtp);
+      l_push_char (dtp, c);
+      if (!is_separator (c))
+       {
+         if (c != 'i' && c != 'I')
+           goto unwind;
+         c = next_char (dtp);
+         l_push_char (dtp, c);
+         if (c != 'n' && c != 'N')
+           goto unwind;
+         c = next_char (dtp);
+         l_push_char (dtp, c);
+         if (c != 'i' && c != 'I')
+           goto unwind;
+         c = next_char (dtp);
+         l_push_char (dtp, c);
+         if (c != 't' && c != 'T')
+           goto unwind;
+         c = next_char (dtp);
+         l_push_char (dtp, c);
+         if (c != 'y' && c != 'Y')
+           goto unwind;
+         c = next_char (dtp);
+         l_push_char (dtp, c);
+       }
+       is_inf = 1;
+    } /* Match NaN.  */
+  else
+    {
+      c = next_char (dtp);
+      l_push_char (dtp, c);
+      if (c != 'a' && c != 'A')
+       goto unwind;
+      c = next_char (dtp);
+      l_push_char (dtp, c);
+      if (c != 'n' && c != 'N')
+       goto unwind;
+      c = next_char (dtp);
+      l_push_char (dtp, c);
+    }
+
+  if (!is_separator (c))
+    goto unwind;
+
+  if (dtp->u.p.namelist_mode)
+    {  
+      if (c == ' ' || c =='\n' || c == '\r')
+       {
+         do
+           c = next_char (dtp);
+         while (c == ' ' || c =='\n' || c == '\r');
+
+         l_push_char (dtp, c);
+
+         if (c == '=')
+           goto unwind;
+       }
+    }
+
+  if (is_inf)
+    {
+      push_char (dtp, 'i');
+      push_char (dtp, 'n');
+      push_char (dtp, 'f');
+    }
+  else
+    {
+      push_char (dtp, 'n');
+      push_char (dtp, 'a');
+      push_char (dtp, 'n');
+    }
+
+  free_line (dtp);
+  goto done;
+
+ unwind:
+  if (dtp->u.p.namelist_mode)
+    {
+      dtp->u.p.nml_read_error = 1;
+      dtp->u.p.line_buffer_enabled = 1;
+      dtp->u.p.item_count = 0;
+      return;
+    }
+
  bad_real:
 
   if (nml_bad_return (dtp, c))
     return;
 
-  st_sprintf (message, "Bad real number in item %d of list input",
+  eat_line (dtp);
+  free_saved (dtp);
+  sprintf (message, "Bad real number in item %d of list input",
              dtp->u.p.item_count);
-
-  generate_error (&dtp->common, ERROR_READ_VALUE, message);
+  generate_error (&dtp->common, LIBERROR_READ_VALUE, message);
 }
 
 
@@ -1245,11 +1642,11 @@ check_type (st_parameter_dt *dtp, bt type, int len)
 
   if (dtp->u.p.saved_type != BT_NULL && dtp->u.p.saved_type != type)
     {
-      st_sprintf (message, "Read type %s where %s was expected for item %d",
+      sprintf (message, "Read type %s where %s was expected for item %d",
                  type_name (dtp->u.p.saved_type), type_name (type),
                  dtp->u.p.item_count);
 
-      generate_error (&dtp->common, ERROR_READ_VALUE, message);
+      generate_error (&dtp->common, LIBERROR_READ_VALUE, message);
       return 1;
     }
 
@@ -1258,11 +1655,11 @@ check_type (st_parameter_dt *dtp, bt type, int len)
 
   if (dtp->u.p.saved_length != len)
     {
-      st_sprintf (message,
+      sprintf (message,
                  "Read kind %d %s where kind %d is required for item %d",
                  dtp->u.p.saved_length, type_name (dtp->u.p.saved_type), len,
                  dtp->u.p.item_count);
-      generate_error (&dtp->common, ERROR_READ_VALUE, message);
+      generate_error (&dtp->common, LIBERROR_READ_VALUE, message);
       return 1;
     }
 
@@ -1276,11 +1673,12 @@ check_type (st_parameter_dt *dtp, bt type, int len)
    greater than one, we copy the data item multiple times.  */
 
 static void
-list_formatted_read_scalar (st_parameter_dt *dtp, bt type, void *p, int kind,
-                           size_t size)
+list_formatted_read_scalar (st_parameter_dt *dtp, volatile bt type, void *p,
+                           int kind, size_t size)
 {
   char c;
-  int m;
+  gfc_char4_t *q;
+  int i, m;
   jmp_buf eof_jump;
 
   dtp->u.p.namelist_mode = 0;
@@ -1288,7 +1686,12 @@ list_formatted_read_scalar (st_parameter_dt *dtp, bt type, void *p, int kind,
   dtp->u.p.eof_jump = &eof_jump;
   if (setjmp (eof_jump))
     {
-      generate_error (&dtp->common, ERROR_END, NULL);
+      generate_error (&dtp->common, LIBERROR_END, NULL);
+      if (!is_internal_unit (dtp))
+       {
+         dtp->u.p.current_unit->endfile = AFTER_ENDFILE;
+         dtp->u.p.current_unit->current_record = 0;
+       }
       goto cleanup;
     }
 
@@ -1298,37 +1701,47 @@ list_formatted_read_scalar (st_parameter_dt *dtp, bt type, void *p, int kind,
       dtp->u.p.input_complete = 0;
       dtp->u.p.repeat_count = 1;
       dtp->u.p.at_eol = 0;
-
+      
       c = eat_spaces (dtp);
       if (is_separator (c))
-       {                       /* Found a null value.  */
+       {
+         /* Found a null value.  */
          eat_separator (dtp);
          dtp->u.p.repeat_count = 0;
+
+         /* eat_separator sets this flag if the separator was a comma.  */
+         if (dtp->u.p.comma_flag)
+           goto cleanup;
+
+         /* eat_separator sets this flag if the separator was a \n or \r.  */
          if (dtp->u.p.at_eol)
            finish_separator (dtp);
-          else
+         else
            goto cleanup;
        }
 
     }
   else
     {
-      if (dtp->u.p.input_complete)
-       goto cleanup;
-
       if (dtp->u.p.repeat_count > 0)
        {
          if (check_type (dtp, type, kind))
            return;
          goto set_value;
        }
+       
+      if (dtp->u.p.input_complete)
+       goto cleanup;
+
+      if (dtp->u.p.input_complete)
+       goto cleanup;
 
       if (dtp->u.p.at_eol)
        finish_separator (dtp);
       else
         {
          eat_spaces (dtp);
-          /* trailing spaces prior to end of line */
+          /* Trailing spaces prior to end of line.  */
          if (dtp->u.p.at_eol)
            finish_separator (dtp);
         }
@@ -1349,10 +1762,16 @@ list_formatted_read_scalar (st_parameter_dt *dtp, bt type, void *p, int kind,
       read_character (dtp, kind);
       break;
     case BT_REAL:
-      read_real (dtp, kind);
+      read_real (dtp, p, kind);
+      /* Copy value back to temporary if needed.  */
+      if (dtp->u.p.repeat_count > 0)
+       memcpy (dtp->u.p.value, p, kind);
       break;
     case BT_COMPLEX:
-      read_complex (dtp, kind, size);
+      read_complex (dtp, p, kind, size);
+      /* Copy value back to temporary if needed.  */
+      if (dtp->u.p.repeat_count > 0)
+       memcpy (dtp->u.p.value, p, size);
       break;
     default:
       internal_error (&dtp->common, "Bad type for list read");
@@ -1368,25 +1787,45 @@ list_formatted_read_scalar (st_parameter_dt *dtp, bt type, void *p, int kind,
   switch (dtp->u.p.saved_type)
     {
     case BT_COMPLEX:
-    case BT_INTEGER:
     case BT_REAL:
+      if (dtp->u.p.repeat_count > 0)
+       memcpy (p, dtp->u.p.value, size);
+      break;
+
+    case BT_INTEGER:
     case BT_LOGICAL:
       memcpy (p, dtp->u.p.value, size);
       break;
 
     case BT_CHARACTER:
       if (dtp->u.p.saved_string)
-       {
+       {
          m = ((int) size < dtp->u.p.saved_used)
              ? (int) size : dtp->u.p.saved_used;
-         memcpy (p, dtp->u.p.saved_string, m);
-       }
+         if (kind == 1)
+           memcpy (p, dtp->u.p.saved_string, m);
+         else
+           {
+             q = (gfc_char4_t *) p;
+             for (i = 0; i < m; i++)
+               q[i] = (unsigned char) dtp->u.p.saved_string[i];
+           }
+       }
       else
        /* Just delimiters encountered, nothing to copy but SPACE.  */
         m = 0;
 
       if (m < (int) size)
-       memset (((char *) p) + m, ' ', size - m);
+       {
+         if (kind == 1)
+           memset (((char *) p) + m, ' ', size - m);
+         else
+           {
+             q = (gfc_char4_t *) p;
+             for (i = m; i < (int) size; i++)
+               q[i] = (unsigned char) ' ';
+           }
+       }
       break;
 
     case BT_NULL:
@@ -1407,6 +1846,8 @@ list_formatted_read (st_parameter_dt *dtp, bt type, void *p, int kind,
 {
   size_t elem;
   char *tmp;
+  size_t stride = type == BT_CHARACTER ?
+                 size * GFC_SIZE_OF_CHAR_KIND(kind) : size;
 
   tmp = (char *) p;
 
@@ -1414,7 +1855,7 @@ list_formatted_read (st_parameter_dt *dtp, bt type, void *p, int kind,
   for (elem = 0; elem < nelems; elem++)
     {
       dtp->u.p.item_count++;
-      list_formatted_read_scalar (dtp, type, tmp + size*elem, kind, size);
+      list_formatted_read_scalar (dtp, type, tmp + stride*elem, kind, size);
     }
 }
 
@@ -1428,6 +1869,8 @@ finish_list_read (st_parameter_dt *dtp)
 
   free_saved (dtp);
 
+  fbuf_flush (dtp->u.p.current_unit, dtp->u.p.mode);
+
   if (dtp->u.p.at_eol)
     {
       dtp->u.p.at_eol = 0;
@@ -1439,6 +1882,13 @@ finish_list_read (st_parameter_dt *dtp)
       c = next_char (dtp);
     }
   while (c != '\n');
+
+  if (dtp->u.p.current_unit->endfile != NO_ENDFILE)
+    {
+      generate_error (&dtp->common, LIBERROR_END, NULL);
+      dtp->u.p.current_unit->endfile = AFTER_ENDFILE;
+      dtp->u.p.current_unit->current_record = 0;
+    }
 }
 
 /*                     NAMELIST INPUT
@@ -1448,7 +1898,7 @@ calls:
    static void nml_match_name (char *name, int len)
    static int nml_query (st_parameter_dt *dtp)
    static int nml_get_obj_data (st_parameter_dt *dtp,
-                               namelist_info **prev_nl, char *)
+                               namelist_info **prev_nl, char *, size_t)
 calls:
       static void nml_untouch_nodes (st_parameter_dt *dtp)
       static namelist_info * find_nml_node (st_parameter_dt *dtp,
@@ -1457,7 +1907,7 @@ calls:
                                     array_loop_spec * ls, int rank, char *)
       static void nml_touch_nodes (namelist_info * nl)
       static int nml_read_obj (namelist_info *nl, index_type offset,
-                              namelist_info **prev_nl, char *,
+                              namelist_info **prev_nl, char *, size_t,
                               index_type clow, index_type chigh)
 calls:
       -itself-  */
@@ -1467,14 +1917,27 @@ calls:
 
 static try
 nml_parse_qualifier (st_parameter_dt *dtp, descriptor_dimension *ad,
-                    array_loop_spec *ls, int rank, char *parse_err_msg)
+                    array_loop_spec *ls, int rank, char *parse_err_msg,
+                    int *parsed_rank)
 {
   int dim;
   int indx;
   int neg;
   int null_flag;
+  int is_array_section, is_char;
   char c;
 
+  is_char = 0;
+  is_array_section = 0;
+  dtp->u.p.expanded_read = 0;
+
+  /* See if this is a character substring qualifier we are looking for.  */
+  if (rank == -1)
+    {
+      rank = 1;
+      is_char = 1;
+    }
+
   /* The next character in the stream should be the '('.  */
 
   c = next_char (dtp);
@@ -1513,14 +1976,17 @@ nml_parse_qualifier (st_parameter_dt *dtp, descriptor_dimension *ad,
              switch (c)
                {
                case ':':
+                  is_array_section = 1;
                  break;
 
                case ',': case ')':
                  if ((c==',' && dim == rank -1)
                      || (c==')' && dim < rank -1))
                    {
-                     st_sprintf (parse_err_msg,
-                                 "Bad number of index fields");
+                     if (is_char)
+                       sprintf (parse_err_msg, "Bad substring qualifier");
+                     else
+                       sprintf (parse_err_msg, "Bad number of index fields");
                      goto err_ret;
                    }
                  break;
@@ -1535,21 +2001,38 @@ nml_parse_qualifier (st_parameter_dt *dtp, descriptor_dimension *ad,
                  break;
 
                default:
-                 st_sprintf (parse_err_msg, "Bad character in index");
+                 if (is_char)
+                   sprintf (parse_err_msg,
+                            "Bad character in substring qualifier");
+                 else
+                   sprintf (parse_err_msg, "Bad character in index");
                  goto err_ret;
                }
 
              if ((c == ',' || c == ')') && indx == 0
                  && dtp->u.p.saved_string == 0)
                {
-                 st_sprintf (parse_err_msg, "Null index field");
+                 if (is_char)
+                   sprintf (parse_err_msg, "Null substring qualifier");
+                 else
+                   sprintf (parse_err_msg, "Null index field");
                  goto err_ret;
                }
 
              if ((c == ':' && indx == 1 && dtp->u.p.saved_string == 0)
                  || (indx == 2 && dtp->u.p.saved_string == 0))
                {
-                 st_sprintf(parse_err_msg, "Bad index triplet");
+                 if (is_char)
+                   sprintf (parse_err_msg, "Bad substring qualifier");
+                 else
+                   sprintf (parse_err_msg, "Bad index triplet");
+                 goto err_ret;
+               }
+
+             if (is_char && !is_array_section)
+               {
+                 sprintf (parse_err_msg,
+                          "Missing colon in substring qualifier");
                  goto err_ret;
                }
 
@@ -1565,7 +2048,10 @@ nml_parse_qualifier (st_parameter_dt *dtp, descriptor_dimension *ad,
              /* Now read the index.  */
              if (convert_integer (dtp, sizeof(ssize_t), neg))
                {
-                 st_sprintf (parse_err_msg, "Bad integer in index");
+                 if (is_char)
+                   sprintf (parse_err_msg, "Bad integer substring qualifier");
+                 else
+                   sprintf (parse_err_msg, "Bad integer in index");
                  goto err_ret;
                }
              break;
@@ -1588,25 +2074,41 @@ nml_parse_qualifier (st_parameter_dt *dtp, descriptor_dimension *ad,
              if (indx == 0)
                {
                  memcpy (&ls[dim].start, dtp->u.p.value, sizeof(ssize_t));
-                 ls[dim].end = ls[dim].start;
+
+                 /*  If -std=f95/2003 or an array section is specified,
+                     do not allow excess data to be processed.  */
+                  if (is_array_section == 1
+                     || compile_options.allow_std < GFC_STD_GNU)
+                   ls[dim].end = ls[dim].start;
+                 else
+                   dtp->u.p.expanded_read = 1;
                }
+
+             /* Check for non-zero rank.  */
+             if (is_array_section == 1 && ls[dim].start != ls[dim].end)
+               *parsed_rank = 1;
+
              break;
            }
        }
 
       /* Check the values of the triplet indices.  */
-      if ((ls[dim].start > (ssize_t)ad[dim].ubound)
-         || (ls[dim].start < (ssize_t)ad[dim].lbound)
-         || (ls[dim].end > (ssize_t)ad[dim].ubound)
-         || (ls[dim].end < (ssize_t)ad[dim].lbound))
+      if ((ls[dim].start > (ssize_t) GFC_DIMENSION_UBOUND(ad[dim]))
+          || (ls[dim].start < (ssize_t) GFC_DIMENSION_LBOUND(ad[dim]))
+          || (ls[dim].end > (ssize_t) GFC_DIMENSION_UBOUND(ad[dim]))
+          || (ls[dim].end < (ssize_t) GFC_DIMENSION_LBOUND(ad[dim])))
        {
-         st_sprintf (parse_err_msg, "Index %d out of range", dim + 1);
+         if (is_char)
+           sprintf (parse_err_msg, "Substring out of range");
+         else
+           sprintf (parse_err_msg, "Index %d out of range", dim + 1);
          goto err_ret;
        }
+
       if (((ls[dim].end - ls[dim].start ) * ls[dim].step < 0)
          || (ls[dim].step == 0))
        {
-         st_sprintf (parse_err_msg, "Bad range in index %d", dim + 1);
+         sprintf (parse_err_msg, "Bad range in index %d", dim + 1);
          goto err_ret;
        }
 
@@ -1648,8 +2150,8 @@ nml_touch_nodes (namelist_info * nl)
   index_type len = strlen (nl->var_name) + 1;
   int dim;
   char * ext_name = (char*)get_mem (len + 1);
-  strcpy (ext_name, nl->var_name);
-  strcat (ext_name, "%");
+  memcpy (ext_name, nl->var_name, len-1);
+  memcpy (ext_name + len - 1, "%", 2);
   for (nl = nl->next; nl; nl = nl->next)
     {
       if (strncmp (nl->var_name, ext_name, len) == 0)
@@ -1658,8 +2160,8 @@ nml_touch_nodes (namelist_info * nl)
          for (dim=0; dim < nl->var_rank; dim++)
            {
              nl->ls[dim].step = 1;
-             nl->ls[dim].end = nl->dim[dim].ubound;
-             nl->ls[dim].start = nl->dim[dim].lbound;
+             nl->ls[dim].end = GFC_DESCRIPTOR_UBOUND(nl,dim);
+             nl->ls[dim].start = GFC_DESCRIPTOR_LBOUND(nl,dim);
              nl->ls[dim].idx = nl->ls[dim].start;
            }
        }
@@ -1714,6 +2216,15 @@ nml_query (st_parameter_dt *dtp, char c)
   namelist_info * nl;
   index_type len;
   char * p;
+#ifdef HAVE_CRLF
+  static const index_type endlen = 3;
+  static const char endl[] = "\r\n";
+  static const char nmlend[] = "&end\r\n";
+#else
+  static const index_type endlen = 2;
+  static const char endl[] = "\n";
+  static const char nmlend[] = "&end\n";
+#endif
 
   if (dtp->u.p.current_unit->unit_number != options.stdin_unit)
     return;
@@ -1737,41 +2248,39 @@ nml_query (st_parameter_dt *dtp, char c)
 
       else
        {
-
          /* "&namelist_name\n"  */
 
          len = dtp->namelist_name_len;
-         p = write_block (dtp, len + 2);
-         if (!p)
-           goto query_return;
+         p = write_block (dtp, len + endlen);
+          if (!p)
+            goto query_return;
          memcpy (p, "&", 1);
          memcpy ((char*)(p + 1), dtp->namelist_name, len);
-         memcpy ((char*)(p + len + 1), "\n", 1);
+         memcpy ((char*)(p + len + 1), &endl, endlen - 1);
          for (nl = dtp->u.p.ionml; nl; nl = nl->next)
            {
-
              /* " var_name\n"  */
 
              len = strlen (nl->var_name);
-             p = write_block (dtp, len + 2);
+              p = write_block (dtp, len + endlen);
              if (!p)
                goto query_return;
              memcpy (p, " ", 1);
              memcpy ((char*)(p + 1), nl->var_name, len);
-             memcpy ((char*)(p + len + 1), "\n", 1);
+             memcpy ((char*)(p + len + 1), &endl, endlen - 1);
            }
 
          /* "&end\n"  */
 
-         p = write_block (dtp, 5);
-         if (!p)
+          p = write_block (dtp, endlen + 3);
            goto query_return;
-         memcpy (p, "&end\n", 5);
+          memcpy (p, &nmlend, endlen + 3);
        }
 
       /* Flush the stream to force immediate output.  */
 
-      flush (dtp->u.p.current_unit->s);
+      fbuf_flush (dtp->u.p.current_unit, WRITING);
+      sflush (dtp->u.p.current_unit->s);
       unlock_unit (dtp->u.p.current_unit);
     }
 
@@ -1797,9 +2306,8 @@ query_return:
 static try
 nml_read_obj (st_parameter_dt *dtp, namelist_info * nl, index_type offset,
              namelist_info **pprev_nl, char *nml_err_msg,
-             index_type clow, index_type chigh)
+             size_t nml_err_msg_size, index_type clow, index_type chigh)
 {
-
   namelist_info * cmp;
   char * obj_name;
   int nml_carry;
@@ -1807,8 +2315,8 @@ nml_read_obj (st_parameter_dt *dtp, namelist_info * nl, index_type offset,
   int dim;
   index_type dlen;
   index_type m;
-  index_type obj_name_len;
-  void * pdata ;
+  size_t obj_name_len;
+  void * pdata;
 
   /* This object not touched in name parsing.  */
 
@@ -1821,7 +2329,6 @@ nml_read_obj (st_parameter_dt *dtp, namelist_info * nl, index_type offset,
   len = nl->len;
   switch (nl->type)
   {
-
     case GFC_DTYPE_INTEGER:
     case GFC_DTYPE_LOGICAL:
       dlen = len;
@@ -1845,13 +2352,13 @@ nml_read_obj (st_parameter_dt *dtp, namelist_info * nl, index_type offset,
 
   do
     {
-
       /* Update the pointer to the data, using the current index vector  */
 
       pdata = (void*)(nl->mem_pos + offset);
       for (dim = 0; dim < nl->var_rank; dim++)
-       pdata = (void*)(pdata + (nl->ls[dim].idx - nl->dim[dim].lbound) *
-                nl->dim[dim].stride * nl->size);
+       pdata = (void*)(pdata + (nl->ls[dim].idx
+                                - GFC_DESCRIPTOR_LBOUND(nl,dim))
+                       * GFC_DESCRIPTOR_STRIDE(nl,dim) * nl->size);
 
       /* Reset the error flag and try to read next value, if
         dtp->u.p.repeat_count=0  */
@@ -1888,18 +2395,27 @@ nml_read_obj (st_parameter_dt *dtp, namelist_info * nl, index_type offset,
               break;
 
          case GFC_DTYPE_REAL:
-             read_real (dtp, len);
-              break;
+           /* Need to copy data back from the real location to the temp in order
+              to handle nml reads into arrays.  */
+           read_real (dtp, pdata, len);
+           memcpy (dtp->u.p.value, pdata, dlen);
+           break;
 
          case GFC_DTYPE_COMPLEX:
-              read_complex (dtp, len, dlen);
-              break;
+           /* Same as for REAL, copy back to temp.  */
+           read_complex (dtp, pdata, len, dlen);
+           memcpy (dtp->u.p.value, pdata, dlen);
+           break;
 
          case GFC_DTYPE_DERIVED:
            obj_name_len = strlen (nl->var_name) + 1;
            obj_name = get_mem (obj_name_len+1);
-           strcpy (obj_name, nl->var_name);
-           strcat (obj_name, "%");
+           memcpy (obj_name, nl->var_name, obj_name_len-1);
+           memcpy (obj_name + obj_name_len - 1, "%", 2);
+
+           /* If reading a derived type, disable the expanded read warning
+              since a single object can have multiple reads.  */
+           dtp->u.p.expanded_read = 0;
 
            /* Now loop over the components. Update the component pointer
               with the return value from nml_write_obj.  This loop jumps
@@ -1914,8 +2430,8 @@ nml_read_obj (st_parameter_dt *dtp, namelist_info * nl, index_type offset,
              {
 
                if (nml_read_obj (dtp, cmp, (index_type)(pdata - nl->mem_pos),
-                                 pprev_nl, nml_err_msg, clow, chigh)
-                   == FAILURE)
+                                 pprev_nl, nml_err_msg, nml_err_msg_size,
+                                 clow, chigh) == FAILURE)
                  {
                    free_mem (obj_name);
                    return FAILURE;
@@ -1932,8 +2448,8 @@ nml_read_obj (st_parameter_dt *dtp, namelist_info * nl, index_type offset,
            goto incr_idx;
 
           default:
-           st_sprintf (nml_err_msg, "Bad type for namelist object %s",
-                       nl->var_name);
+           snprintf (nml_err_msg, nml_err_msg_size,
+                     "Bad type for namelist object %s", nl->var_name);
            internal_error (&dtp->common, nml_err_msg);
            goto nml_err_ret;
           }
@@ -1946,11 +2462,16 @@ nml_read_obj (st_parameter_dt *dtp, namelist_info * nl, index_type offset,
 
       *pprev_nl = nl;
       if (dtp->u.p.nml_read_error)
-       return SUCCESS;
+       {
+         dtp->u.p.expanded_read = 0;
+         return SUCCESS;
+       }
 
       if (dtp->u.p.saved_type == GFC_DTYPE_UNKNOWN)
-       goto incr_idx;
-
+       {
+         dtp->u.p.expanded_read = 0;
+         goto incr_idx;
+       }
 
       /* Note the switch from GFC_DTYPE_type to BT_type at this point.
         This comes about because the read functions return BT_types.  */
@@ -1971,14 +2492,27 @@ nml_read_obj (st_parameter_dt *dtp, namelist_info * nl, index_type offset,
          memcpy (pdata, dtp->u.p.saved_string, m);
          if (m < dlen)
            memset ((void*)( pdata + m ), ' ', dlen - m);
-       break;
+         break;
 
        default:
          break;
       }
 
-      /* Break out of loop if scalar.  */
+      /* Warn if a non-standard expanded read occurs. A single read of a
+        single object is acceptable.  If a second read occurs, issue a warning
+        and set the flag to zero to prevent further warnings.  */
+      if (dtp->u.p.expanded_read == 2)
+       {
+         notify_std (&dtp->common, GFC_STD_GNU, "Non-standard expanded namelist read.");
+         dtp->u.p.expanded_read = 0;
+       }
+
+      /* If the expanded read warning flag is set, increment it,
+        indicating that a single read has occurred.  */
+      if (dtp->u.p.expanded_read >= 1)
+       dtp->u.p.expanded_read++;
 
+      /* Break out of loop if scalar.  */
       if (!nl->var_rank)
        break;
 
@@ -2003,9 +2537,9 @@ incr_idx:
 
   if (dtp->u.p.repeat_count > 1)
     {
-       st_sprintf (nml_err_msg, "Repeat count too large for namelist object %s" ,
-                  nl->var_name );
-       goto nml_err_ret;
+      snprintf (nml_err_msg, nml_err_msg_size,
+               "Repeat count too large for namelist object %s", nl->var_name);
+      goto nml_err_ret;
     }
   return SUCCESS;
 
@@ -2023,16 +2557,16 @@ nml_err_ret:
 
 static try
 nml_get_obj_data (st_parameter_dt *dtp, namelist_info **pprev_nl,
-                 char *nml_err_msg)
+                 char *nml_err_msg, size_t nml_err_msg_size)
 {
   char c;
   namelist_info * nl;
   namelist_info * first_nl = NULL;
   namelist_info * root_nl = NULL;
-  int dim;
+  int dim, parsed_rank;
   int component_flag;
-  char parse_err_msg[30];
   index_type clow, chigh;
+  int non_zero_rank_count;
 
   /* Look for end of input or object name.  If '?' or '=?' are encountered
      in stdin, print the node names or the namelist to stdout.  */
@@ -2053,7 +2587,7 @@ nml_get_obj_data (st_parameter_dt *dtp, namelist_info **pprev_nl,
       c = next_char (dtp);
       if (c != '?')
        {
-         st_sprintf (nml_err_msg, "namelist read: missplaced = sign");
+         sprintf (nml_err_msg, "namelist read: misplaced = sign");
          goto nml_err_ret;
        }
       nml_query (dtp, '=');
@@ -2068,7 +2602,7 @@ nml_get_obj_data (st_parameter_dt *dtp, namelist_info **pprev_nl,
       nml_match_name (dtp, "end", 3);
       if (dtp->u.p.nml_read_error)
        {
-         st_sprintf (nml_err_msg, "namelist not terminated with / or &end");
+         sprintf (nml_err_msg, "namelist not terminated with / or &end");
          goto nml_err_ret;
        }
     case '/':
@@ -2084,6 +2618,7 @@ nml_get_obj_data (st_parameter_dt *dtp, namelist_info **pprev_nl,
 
   nml_untouch_nodes (dtp);
   component_flag = 0;
+  non_zero_rank_count = 0;
 
   /* Get the object name - should '!' and '\n' be permitted separators?  */
 
@@ -2093,7 +2628,8 @@ get_name:
 
   do
     {
-      push_char (dtp, tolower(c));
+      if (!is_separator (c))
+       push_char (dtp, tolower(c));
       c = next_char (dtp);
     } while (!( c=='=' || c==' ' || c=='\t' || c =='(' || c =='%' ));
 
@@ -2127,12 +2663,13 @@ get_name:
   if (nl == NULL)
     {
       if (dtp->u.p.nml_read_error && *pprev_nl)
-       st_sprintf (nml_err_msg, "Bad data for namelist object %s",
-                   (*pprev_nl)->var_name);
+       snprintf (nml_err_msg, nml_err_msg_size,
+                 "Bad data for namelist object %s", (*pprev_nl)->var_name);
 
       else
-       st_sprintf (nml_err_msg, "Cannot match namelist object name %s",
-                   dtp->u.p.saved_string);
+       snprintf (nml_err_msg, nml_err_msg_size,
+                 "Cannot match namelist object name %s",
+                 dtp->u.p.saved_string);
 
       goto nml_err_ret;
     }
@@ -2143,8 +2680,8 @@ get_name:
   for (dim=0; dim < nl->var_rank; dim++)
     {
       nl->ls[dim].step = 1;
-      nl->ls[dim].end = nl->dim[dim].ubound;
-      nl->ls[dim].start = nl->dim[dim].lbound;
+      nl->ls[dim].end = GFC_DESCRIPTOR_UBOUND(nl,dim);
+      nl->ls[dim].start = GFC_DESCRIPTOR_LBOUND(nl,dim);
       nl->ls[dim].idx = nl->ls[dim].start;
     }
 
@@ -2152,16 +2689,25 @@ get_name:
 
   if (c == '(' && nl->var_rank)
     {
+      parsed_rank = 0;
       if (nml_parse_qualifier (dtp, nl->dim, nl->ls, nl->var_rank,
-                              parse_err_msg) == FAILURE)
+                              nml_err_msg, &parsed_rank) == FAILURE)
        {
-         st_sprintf (nml_err_msg, "%s for namelist variable %s",
-                     parse_err_msg, nl->var_name);
+         char *nml_err_msg_end = strchr (nml_err_msg, '\0');
+         snprintf (nml_err_msg_end,
+                   nml_err_msg_size - (nml_err_msg_end - nml_err_msg),
+                   " for namelist variable %s", nl->var_name);
          goto nml_err_ret;
        }
+
+      if (parsed_rank > 0)
+       non_zero_rank_count++;
+
       c = next_char (dtp);
       unget_char (dtp, c);
     }
+  else if (nl->var_rank > 0)
+    non_zero_rank_count++;
 
   /* Now parse a derived type component. The root namelist_info address
      is backed up, as is the previous component level.  The  component flag
@@ -2169,11 +2715,10 @@ get_name:
 
   if (c == '%')
     {
-
       if (nl->type != GFC_DTYPE_DERIVED)
        {
-         st_sprintf (nml_err_msg, "Attempt to get derived component for %s",
-                     nl->var_name);
+         snprintf (nml_err_msg, nml_err_msg_size,
+                   "Attempt to get derived component for %s", nl->var_name);
          goto nml_err_ret;
        }
 
@@ -2184,7 +2729,6 @@ get_name:
       component_flag = 1;
       c = next_char (dtp);
       goto get_name;
-
     }
 
   /* Parse a character qualifier, if present.  chigh = 0 is a default
@@ -2198,10 +2742,13 @@ get_name:
       descriptor_dimension chd[1] = { {1, clow, nl->string_length} };
       array_loop_spec ind[1] = { {1, clow, nl->string_length, 1} };
 
-      if (nml_parse_qualifier (dtp, chd, ind, 1, parse_err_msg) == FAILURE)
+      if (nml_parse_qualifier (dtp, chd, ind, -1, nml_err_msg, &parsed_rank)
+         == FAILURE)
        {
-         st_sprintf (nml_err_msg, "%s for namelist variable %s",
-                     parse_err_msg, nl->var_name);
+         char *nml_err_msg_end = strchr (nml_err_msg, '\0');
+         snprintf (nml_err_msg_end,
+                   nml_err_msg_size - (nml_err_msg_end - nml_err_msg),
+                   " for namelist variable %s", nl->var_name);
          goto nml_err_ret;
        }
 
@@ -2210,9 +2757,9 @@ get_name:
 
       if (ind[0].step != 1)
        {
-         st_sprintf (nml_err_msg,
-                     "Bad step in substring for namelist object %s",
-                     nl->var_name);
+         snprintf (nml_err_msg, nml_err_msg_size,
+                   "Step not allowed in substring qualifier"
+                   " for namelist object %s", nl->var_name);
          goto nml_err_ret;
        }
 
@@ -2226,15 +2773,26 @@ get_name:
 
   if (nl->type == GFC_DTYPE_DERIVED)
     nml_touch_nodes (nl);
-  if (component_flag)
+  if (component_flag && nl->var_rank > 0 && nl->next)
     nl = first_nl;
 
-  /*make sure no extraneous qualifiers are there.*/
+  /* Make sure no extraneous qualifiers are there.  */
 
   if (c == '(')
     {
-      st_sprintf (nml_err_msg, "Qualifier for a scalar or non-character"
-                 " namelist object %s", nl->var_name);
+      snprintf (nml_err_msg, nml_err_msg_size,
+               "Qualifier for a scalar or non-character namelist object %s",
+               nl->var_name);
+      goto nml_err_ret;
+    }
+
+  /* Make sure there is no more than one non-zero rank object.  */
+  if (non_zero_rank_count > 1)
+    {
+      snprintf (nml_err_msg, nml_err_msg_size,
+               "Multiple sub-objects with non-zero rank in namelist object %s",
+               nl->var_name);
+      non_zero_rank_count = 0;
       goto nml_err_ret;
     }
 
@@ -2257,12 +2815,17 @@ get_name:
 
   if (c != '=')
     {
-      st_sprintf (nml_err_msg, "Equal sign must follow namelist object name %s",
-                 nl->var_name);
+      snprintf (nml_err_msg, nml_err_msg_size,
+               "Equal sign must follow namelist object name %s",
+               nl->var_name);
       goto nml_err_ret;
     }
 
-  if (nml_read_obj (dtp, nl, 0, pprev_nl, nml_err_msg, clow, chigh) == FAILURE)
+  if (first_nl != NULL && first_nl->var_rank > 0)
+    nl = first_nl;
+  
+  if (nml_read_obj (dtp, nl, 0, pprev_nl, nml_err_msg, nml_err_msg_size,
+                   clow, chigh) == FAILURE)
     goto nml_err_ret;
 
   return SUCCESS;
@@ -2281,7 +2844,7 @@ namelist_read (st_parameter_dt *dtp)
 {
   char c;
   jmp_buf eof_jump;
-  char nml_err_msg[100];
+  char nml_err_msg[200];
   /* Pointer to the previously read object, in case attempt is made to read
      new object name.  Should this fail, error message can give previous
      name.  */
@@ -2289,12 +2852,13 @@ namelist_read (st_parameter_dt *dtp)
 
   dtp->u.p.namelist_mode = 1;
   dtp->u.p.input_complete = 0;
+  dtp->u.p.expanded_read = 0;
 
   dtp->u.p.eof_jump = &eof_jump;
   if (setjmp (eof_jump))
     {
       dtp->u.p.eof_jump = NULL;
-      generate_error (&dtp->common, ERROR_END, NULL);
+      generate_error (&dtp->common, LIBERROR_END, NULL);
       return;
     }
 
@@ -2309,6 +2873,10 @@ find_nml_name:
     case '&':
           break;
 
+    case '!':
+      eat_line (dtp);
+      goto find_nml_name;
+
     case '=':
       c = next_char (dtp);
       if (c == '?')
@@ -2331,12 +2899,24 @@ find_nml_name:
   if (dtp->u.p.nml_read_error)
     goto find_nml_name;
 
+  /* A trailing space is required, we give a little lattitude here, 10.9.1.  */ 
+  c = next_char (dtp);
+  if (!is_separator(c) && c != '!')
+    {
+      unget_char (dtp, c);
+      goto find_nml_name;
+    }
+
+  unget_char (dtp, c);
+  eat_separator (dtp);
+
   /* Ready to read namelist objects.  If there is an error in input
      from stdin, output the error message and continue.  */
 
   while (!dtp->u.p.input_complete)
     {
-      if (nml_get_obj_data (dtp, &prev_nl, nml_err_msg) == FAILURE)
+      if (nml_get_obj_data (dtp, &prev_nl, nml_err_msg, sizeof nml_err_msg)
+                           == FAILURE)
        {
          gfc_unit *u;
 
@@ -2347,7 +2927,7 @@ find_nml_name:
          st_printf ("%s\n", nml_err_msg);
          if (u != NULL)
            {
-             flush (u->s);
+             sflush (u->s);
              unlock_unit (u);
            }
         }
@@ -2356,6 +2936,7 @@ find_nml_name:
 
   dtp->u.p.eof_jump = NULL;
   free_saved (dtp);
+  free_line (dtp);
   return;
 
   /* All namelist error calls return from here */
@@ -2364,6 +2945,7 @@ nml_err_ret:
 
   dtp->u.p.eof_jump = NULL;
   free_saved (dtp);
-  generate_error (&dtp->common, ERROR_READ_VALUE, nml_err_msg);
+  free_line (dtp);
+  generate_error (&dtp->common, LIBERROR_READ_VALUE, nml_err_msg);
   return;
 }