OSDN Git Service

2006-08-15 Jerry DeLisle <jvdelisle@gcc.gnu.org>
[pf3gnuchains/gcc-fork.git] / libgfortran / io / transfer.c
index fc06131..99e8979 100644 (file)
@@ -91,7 +91,7 @@ static const st_option advance_opt[] = {
 
 typedef enum
 { FORMATTED_SEQUENTIAL, UNFORMATTED_SEQUENTIAL,
-  FORMATTED_DIRECT, UNFORMATTED_DIRECT
+  FORMATTED_DIRECT, UNFORMATTED_DIRECT, FORMATTED_STREAM, UNFORMATTED_STREAM
 }
 file_mode;
 
@@ -101,16 +101,23 @@ current_mode (st_parameter_dt *dtp)
 {
   file_mode m;
 
+  m = FORM_UNSPECIFIED;
+
   if (dtp->u.p.current_unit->flags.access == ACCESS_DIRECT)
     {
       m = dtp->u.p.current_unit->flags.form == FORM_FORMATTED ?
        FORMATTED_DIRECT : UNFORMATTED_DIRECT;
     }
-  else
+  else if (dtp->u.p.current_unit->flags.access == ACCESS_SEQUENTIAL)
     {
       m = dtp->u.p.current_unit->flags.form == FORM_FORMATTED ?
        FORMATTED_SEQUENTIAL : UNFORMATTED_SEQUENTIAL;
     }
+  else if (dtp->u.p.current_unit->flags.access == ACCESS_STREAM)
+    {
+      m = dtp->u.p.current_unit->flags.form == FORM_FORMATTED ?
+       FORMATTED_STREAM : UNFORMATTED_STREAM;
+    }
 
   return m;
 }
@@ -128,7 +135,7 @@ current_mode (st_parameter_dt *dtp)
    an I/O error.
 
    Given this, the solution is to read a byte at a time, stopping if
-   we hit the newline.  For small locations, we use a static buffer.
+   we hit the newline.  For small allocations, we use a static buffer.
    For larger allocations, we are forced to allocate memory on the
    heap.  Hopefully this won't happen very often.  */
 
@@ -256,56 +263,86 @@ read_block (st_parameter_dt *dtp, int *length)
   char *source;
   int nread;
 
-  if (dtp->u.p.current_unit->bytes_left < *length)
+  if (!is_stream_io (dtp))
     {
-      /* For preconnected units with default record length, set bytes left
-        to unit record length and proceed, otherwise error.  */
-      if (dtp->u.p.current_unit->unit_number == options.stdin_unit
-         && dtp->u.p.current_unit->recl == DEFAULT_RECL)
-        dtp->u.p.current_unit->bytes_left = dtp->u.p.current_unit->recl;
-      else
+      if (dtp->u.p.current_unit->bytes_left < (gfc_offset) *length)
        {
-         if (dtp->u.p.current_unit->flags.pad == PAD_NO)
+         /* For preconnected units with default record length, set bytes left
+          to unit record length and proceed, otherwise error.  */
+         if (dtp->u.p.current_unit->unit_number == options.stdin_unit
+             && dtp->u.p.current_unit->recl == DEFAULT_RECL)
+          dtp->u.p.current_unit->bytes_left = dtp->u.p.current_unit->recl;
+         else
            {
-             /* Not enough data left.  */
-             generate_error (&dtp->common, ERROR_EOR, NULL);
+             if (dtp->u.p.current_unit->flags.pad == PAD_NO)
+               {
+                 /* Not enough data left.  */
+                 generate_error (&dtp->common, ERROR_EOR, NULL);
+                 return NULL;
+               }
+           }
+
+         if (dtp->u.p.current_unit->bytes_left == 0)
+           {
+             dtp->u.p.current_unit->endfile = AT_ENDFILE;
+             generate_error (&dtp->common, ERROR_END, NULL);
              return NULL;
            }
+
+         *length = dtp->u.p.current_unit->bytes_left;
        }
 
-      if (dtp->u.p.current_unit->bytes_left == 0)
+      if (dtp->u.p.current_unit->flags.form == FORM_FORMATTED &&
+       dtp->u.p.current_unit->flags.access == ACCESS_SEQUENTIAL)
+         return read_sf (dtp, length, 0);      /* Special case.  */
+
+      dtp->u.p.current_unit->bytes_left -= (gfc_offset) *length;
+
+      nread = *length;
+      source = salloc_r (dtp->u.p.current_unit->s, &nread);
+
+      if ((dtp->common.flags & IOPARM_DT_HAS_SIZE) != 0)
+       dtp->u.p.size_used += (gfc_offset) nread;
+
+      if (nread != *length)
+       {                               /* Short read, this shouldn't happen.  */
+         if (dtp->u.p.current_unit->flags.pad == PAD_YES)
+           *length = nread;
+         else
+           {
+             generate_error (&dtp->common, ERROR_EOR, NULL);
+             source = NULL;
+           }
+       }
+    }
+  else
+    {
+      if (sseek (dtp->u.p.current_unit->s,
+                (gfc_offset) (dtp->rec - 1)) == FAILURE)
        {
-         dtp->u.p.current_unit->endfile = AT_ENDFILE;
          generate_error (&dtp->common, ERROR_END, NULL);
          return NULL;
        }
 
-      *length = dtp->u.p.current_unit->bytes_left;
-    }
-
-  if (dtp->u.p.current_unit->flags.form == FORM_FORMATTED &&
-      dtp->u.p.current_unit->flags.access == ACCESS_SEQUENTIAL)
-    return read_sf (dtp, length, 0);   /* Special case.  */
-
-  dtp->u.p.current_unit->bytes_left -= *length;
-
-  nread = *length;
-  source = salloc_r (dtp->u.p.current_unit->s, &nread);
+      nread = *length;
+      source = salloc_r (dtp->u.p.current_unit->s, &nread);
 
-  if ((dtp->common.flags & IOPARM_DT_HAS_SIZE) != 0)
-    dtp->u.p.size_used += (gfc_offset) nread;
+      if ((dtp->common.flags & IOPARM_DT_HAS_SIZE) != 0)
+       dtp->u.p.size_used += (gfc_offset) nread;
 
-  if (nread != *length)
-    {                          /* Short read, this shouldn't happen.  */
-      if (dtp->u.p.current_unit->flags.pad == PAD_YES)
-       *length = nread;
-      else
-       {
-         generate_error (&dtp->common, ERROR_EOR, NULL);
-         source = NULL;
+      if (nread != *length)
+       {                               /* Short read, this shouldn't happen.  */
+         if (dtp->u.p.current_unit->flags.pad == PAD_YES)
+           *length = nread;
+         else
+           {
+             generate_error (&dtp->common, ERROR_END, NULL);
+             source = NULL;
+           }
        }
-    }
 
+      dtp->rec += (GFC_IO_INT) nread;
+    }
   return source;
 }
 
@@ -319,44 +356,57 @@ read_block_direct (st_parameter_dt *dtp, void *buf, size_t *nbytes)
   void *data;
   size_t nread;
 
-  if (dtp->u.p.current_unit->bytes_left < *nbytes)
+  if (!is_stream_io (dtp))
     {
-      /* For preconnected units with default record length, set bytes left
-        to unit record length and proceed, otherwise error.  */
-      if (dtp->u.p.current_unit->unit_number == options.stdin_unit
-         && dtp->u.p.current_unit->recl == DEFAULT_RECL)
-        dtp->u.p.current_unit->bytes_left = dtp->u.p.current_unit->recl;
-      else
+      if (dtp->u.p.current_unit->bytes_left < (gfc_offset) *nbytes)
        {
-         if (dtp->u.p.current_unit->flags.pad == PAD_NO)
+         /* For preconnected units with default record length, set
+            bytes left to unit record length and proceed, otherwise
+            error.  */
+         if (dtp->u.p.current_unit->unit_number == options.stdin_unit
+             && dtp->u.p.current_unit->recl == DEFAULT_RECL)
+           dtp->u.p.current_unit->bytes_left = dtp->u.p.current_unit->recl;
+         else
            {
-             /* Not enough data left.  */
-             generate_error (&dtp->common, ERROR_EOR, NULL);
+             if (dtp->u.p.current_unit->flags.pad == PAD_NO)
+               {
+                 /* Not enough data left.  */
+                 generate_error (&dtp->common, ERROR_EOR, NULL);
+                 return;
+               }
+           }
+         
+         if (dtp->u.p.current_unit->bytes_left == 0)
+           {
+             dtp->u.p.current_unit->endfile = AT_ENDFILE;
+             generate_error (&dtp->common, ERROR_END, NULL);
              return;
            }
+
+         *nbytes = (size_t) dtp->u.p.current_unit->bytes_left;
        }
 
-      if (dtp->u.p.current_unit->bytes_left == 0)
+      if (dtp->u.p.current_unit->flags.form == FORM_FORMATTED &&
+         dtp->u.p.current_unit->flags.access == ACCESS_SEQUENTIAL)
        {
-         dtp->u.p.current_unit->endfile = AT_ENDFILE;
-         generate_error (&dtp->common, ERROR_END, NULL);
+         length = (int *) nbytes;
+         data = read_sf (dtp, length, 0);      /* Special case.  */
+         memcpy (buf, data, (size_t) *length);
          return;
        }
 
-      *nbytes = dtp->u.p.current_unit->bytes_left;
+      dtp->u.p.current_unit->bytes_left -= (gfc_offset) *nbytes;
     }
-
-  if (dtp->u.p.current_unit->flags.form == FORM_FORMATTED &&
-      dtp->u.p.current_unit->flags.access == ACCESS_SEQUENTIAL)
+  else
     {
-      length = (int *) nbytes;
-      data = read_sf (dtp, length, 0); /* Special case.  */
-      memcpy (buf, data, (size_t) *length);
-      return;
+      if (sseek (dtp->u.p.current_unit->s,
+         (gfc_offset) (dtp->rec - 1)) == FAILURE)
+       {
+         generate_error (&dtp->common, ERROR_END, NULL);
+         return;
+       }
     }
 
-  dtp->u.p.current_unit->bytes_left -= *nbytes;
-
   nread = *nbytes;
   if (sread (dtp->u.p.current_unit->s, buf, &nread) != 0)
     {
@@ -364,18 +414,20 @@ read_block_direct (st_parameter_dt *dtp, void *buf, size_t *nbytes)
       return;
     }
 
-  if ((dtp->common.flags & IOPARM_DT_HAS_SIZE) != 0)
-    dtp->u.p.size_used += (gfc_offset) nread;
+  if (!is_stream_io (dtp))
+    {
+      if ((dtp->common.flags & IOPARM_DT_HAS_SIZE) != 0)
+       dtp->u.p.size_used += (gfc_offset) nread;
+    }
+  else
+    dtp->rec += (GFC_IO_INT) nread; 
 
-  if (nread != *nbytes)
-    {                          /* Short read, e.g. if we hit EOF.  */
-      if (dtp->u.p.current_unit->flags.pad == PAD_YES)
-       {
-         memset (((char *) buf) + nread, ' ', *nbytes - nread);
-         *nbytes = nread;
-       }
-      else
+  if (nread != *nbytes)  /* Short read, e.g. if we hit EOF.  */
+    {
+      if (!is_stream_io (dtp))
        generate_error (&dtp->common, ERROR_EOR, NULL);
+      else
+       generate_error (&dtp->common, ERROR_END, NULL);   
     }
 }
 
@@ -390,35 +442,59 @@ write_block (st_parameter_dt *dtp, int length)
 {
   char *dest;
 
-  if (dtp->u.p.current_unit->bytes_left < length)
+  if (!is_stream_io (dtp))
     {
-      /* For preconnected units with default record length, set bytes left
-        to unit record length and proceed, otherwise error.  */
-      if ((dtp->u.p.current_unit->unit_number == options.stdout_unit
-         || dtp->u.p.current_unit->unit_number == options.stderr_unit)
-         && dtp->u.p.current_unit->recl == DEFAULT_RECL)
-        dtp->u.p.current_unit->bytes_left = dtp->u.p.current_unit->recl;
-      else
+      if (dtp->u.p.current_unit->bytes_left < (gfc_offset) length)
        {
-         generate_error (&dtp->common, ERROR_EOR, NULL);
-         return NULL;
+         /* For preconnected units with default record length, set bytes left
+            to unit record length and proceed, otherwise error.  */
+         if ((dtp->u.p.current_unit->unit_number == options.stdout_unit
+               || dtp->u.p.current_unit->unit_number == options.stderr_unit)
+               && dtp->u.p.current_unit->recl == DEFAULT_RECL)
+           dtp->u.p.current_unit->bytes_left = dtp->u.p.current_unit->recl;
+         else
+           {
+             generate_error (&dtp->common, ERROR_EOR, NULL);
+             return NULL;
+           }
        }
-    }
 
-  dtp->u.p.current_unit->bytes_left -= (gfc_offset) length;
-  dest = salloc_w (dtp->u.p.current_unit->s, &length);
+      dtp->u.p.current_unit->bytes_left -= (gfc_offset) length;
+
+
+      dest = salloc_w (dtp->u.p.current_unit->s, &length);
   
-  if (dest == NULL)
-    {
-      generate_error (&dtp->common, ERROR_END, NULL);
-      return NULL;
+      if (dest == NULL)
+       {
+         generate_error (&dtp->common, ERROR_END, NULL);
+         return NULL;
+       }
+
+      if (is_internal_unit (dtp) && dtp->u.p.current_unit->endfile == AT_ENDFILE)
+       generate_error (&dtp->common, ERROR_END, NULL);
+
+      if ((dtp->common.flags & IOPARM_DT_HAS_SIZE) != 0)
+       dtp->u.p.size_used += (gfc_offset) length;
     }
+  else
+    {
+      if (sseek (dtp->u.p.current_unit->s,
+         (gfc_offset) (dtp->rec - 1)) == FAILURE)
+       {
+         generate_error (&dtp->common, ERROR_END, NULL);
+         return NULL;
+       }
 
-  if (is_internal_unit (dtp) && dtp->u.p.current_unit->endfile == AT_ENDFILE)
-    generate_error (&dtp->common, ERROR_END, NULL);
+      dest = salloc_w (dtp->u.p.current_unit->s, &length);
 
-  if ((dtp->common.flags & IOPARM_DT_HAS_SIZE) != 0)
-    dtp->u.p.size_used += (gfc_offset) length;
+      if (dest == NULL)
+       {
+         generate_error (&dtp->common, ERROR_END, NULL);
+         return NULL;
+       }
+
+      dtp->rec += (GFC_IO_INT) length;
+    }
 
   return dest;
 }
@@ -429,34 +505,52 @@ write_block (st_parameter_dt *dtp, int length)
 static try
 write_buf (st_parameter_dt *dtp, void *buf, size_t nbytes)
 {
-  if (dtp->u.p.current_unit->bytes_left < nbytes)
+  if (!is_stream_io (dtp))
     {
-      /* For preconnected units with default record length, set bytes left
-        to unit record length and proceed, otherwise error.  */
-      if ((dtp->u.p.current_unit->unit_number == options.stdout_unit
-         || dtp->u.p.current_unit->unit_number == options.stderr_unit)
-         && dtp->u.p.current_unit->recl == DEFAULT_RECL)
-        dtp->u.p.current_unit->bytes_left = dtp->u.p.current_unit->recl;
-      else
+      if (dtp->u.p.current_unit->bytes_left < (gfc_offset) nbytes)
        {
-         if (dtp->u.p.current_unit->flags.access == ACCESS_DIRECT)
-           generate_error (&dtp->common, ERROR_DIRECT_EOR, NULL);
+         /* For preconnected units with default record length, set
+            bytes left to unit record length and proceed, otherwise
+            error.  */
+         if ((dtp->u.p.current_unit->unit_number == options.stdout_unit
+              || dtp->u.p.current_unit->unit_number == options.stderr_unit)
+             && dtp->u.p.current_unit->recl == DEFAULT_RECL)
+           dtp->u.p.current_unit->bytes_left = dtp->u.p.current_unit->recl;
          else
-           generate_error (&dtp->common, ERROR_EOR, NULL);
+           {
+             if (dtp->u.p.current_unit->flags.access == ACCESS_DIRECT)
+               generate_error (&dtp->common, ERROR_DIRECT_EOR, NULL);
+             else
+               generate_error (&dtp->common, ERROR_EOR, NULL);
+             return FAILURE;
+           }
+       }
+
+      dtp->u.p.current_unit->bytes_left -= (gfc_offset) nbytes;
+    }
+  else
+    {
+      if (sseek (dtp->u.p.current_unit->s,
+                (gfc_offset) (dtp->rec - 1)) == FAILURE)
+       {
+         generate_error (&dtp->common, ERROR_OS, NULL);
          return FAILURE;
        }
     }
 
-  dtp->u.p.current_unit->bytes_left -= (gfc_offset) nbytes;
-
   if (swrite (dtp->u.p.current_unit->s, buf, &nbytes) != 0)
     {
       generate_error (&dtp->common, ERROR_OS, NULL);
       return FAILURE;
     }
 
-  if ((dtp->common.flags & IOPARM_DT_HAS_SIZE) != 0)
-    dtp->u.p.size_used += (gfc_offset) nbytes;
+  if (!is_stream_io (dtp))
+    {
+      if ((dtp->common.flags & IOPARM_DT_HAS_SIZE) != 0)
+       dtp->u.p.size_used += (gfc_offset) nbytes;
+    }
+  else
+    dtp->rec += (GFC_IO_INT) nbytes; 
 
   return SUCCESS;
 }
@@ -469,18 +563,19 @@ unformatted_read (st_parameter_dt *dtp, bt type,
                  void *dest, int kind,
                  size_t size, size_t nelems)
 {
+  size_t i, sz;
+
   /* Currently, character implies size=1.  */
   if (dtp->u.p.current_unit->flags.convert == CONVERT_NATIVE
       || size == 1 || type == BT_CHARACTER)
     {
-      size *= nelems;
-      read_block_direct (dtp, dest, &size);
+      sz = size * nelems;
+      read_block_direct (dtp, dest, &sz);
     }
   else
     {
       char buffer[16];
       char *p;
-      size_t i, sz;
       
       /* Break up complex into its constituent reals.  */
       if (type == BT_COMPLEX)
@@ -721,7 +816,8 @@ formatted_transfer_scalar (st_parameter_dt *dtp, bt type, void *p, int len,
          dtp->u.p.skips = dtp->u.p.pending_spaces = 0;
        }
 
-      bytes_used = (int)(dtp->u.p.current_unit->recl - dtp->u.p.current_unit->bytes_left);
+      bytes_used = (int)(dtp->u.p.current_unit->recl
+                        - dtp->u.p.current_unit->bytes_left);
 
       switch (t)
        {
@@ -1405,6 +1501,14 @@ pre_position (st_parameter_dt *dtp)
 
   switch (current_mode (dtp))
     {
+    case FORMATTED_STREAM:
+    case UNFORMATTED_STREAM:
+      /* There are no records with stream I/O.  Set the default position
+        to the beginning of the file if no position was specified.  */
+      if ((dtp->common.flags & IOPARM_DT_HAS_REC) == 0)
+        dtp->rec = 1;
+      break;
+    
     case UNFORMATTED_SEQUENTIAL:
       if (dtp->u.p.mode == READING)
        us_read (dtp);
@@ -1549,13 +1653,12 @@ data_transfer_init (st_parameter_dt *dtp, int read_flag)
     generate_error (&dtp->common, ERROR_OPTION_CONFLICT,
                    "Missing format for FORMATTED data transfer");
 
-
   if (is_internal_unit (dtp)
       && dtp->u.p.current_unit->flags.form == FORM_UNFORMATTED)
     generate_error (&dtp->common, ERROR_OPTION_CONFLICT,
                    "Internal file cannot be accessed by UNFORMATTED data transfer");
 
-  /* Check the record number.  */
+  /* Check the record or position number.  */
 
   if (dtp->u.p.current_unit->flags.access == ACCESS_DIRECT
       && (cf & IOPARM_DT_HAS_REC) == 0)
@@ -1628,7 +1731,6 @@ data_transfer_init (st_parameter_dt *dtp, int read_flag)
     return;
 
   /* Sanity checks on the record number.  */
-
   if ((cf & IOPARM_DT_HAS_REC) != 0)
     {
       if (dtp->rec <= 0)
@@ -1664,8 +1766,8 @@ data_transfer_init (st_parameter_dt *dtp, int read_flag)
        }
 
       /* Position the file.  */
-      if (sseek (dtp->u.p.current_unit->s,
-              (dtp->rec - 1) * dtp->u.p.current_unit->recl) == FAILURE)
+      if (sseek (dtp->u.p.current_unit->s, (gfc_offset) (dtp->rec - 1)
+                 * dtp->u.p.current_unit->recl) == FAILURE)
        {
          generate_error (&dtp->common, ERROR_OS, NULL);
          return;
@@ -1723,7 +1825,7 @@ data_transfer_init (st_parameter_dt *dtp, int read_flag)
 
   if (read_flag)
     {
-      if (dtp->u.p.current_unit->read_bad)
+      if (dtp->u.p.current_unit->read_bad && !is_stream_io (dtp))
        {
          generate_error (&dtp->common, ERROR_BAD_OPTION,
                          "Cannot READ after a nonadvancing WRITE");
@@ -1813,6 +1915,11 @@ next_record_r (st_parameter_dt *dtp)
 
   switch (current_mode (dtp))
     {
+    /* No records in STREAM I/O.  */
+    case FORMATTED_STREAM:
+    case UNFORMATTED_STREAM:
+      return;
+    
     case UNFORMATTED_SEQUENTIAL:
 
       /* Skip over tail */
@@ -2003,6 +2110,11 @@ next_record_w (st_parameter_dt *dtp, int done)
 
   switch (current_mode (dtp))
     {
+    /* No records in STREAM I/O.  */
+    case FORMATTED_STREAM:
+    case UNFORMATTED_STREAM:
+      return;
+
     case FORMATTED_DIRECT:
       if (dtp->u.p.current_unit->bytes_left == 0)
        break;
@@ -2166,6 +2278,9 @@ next_record_w (st_parameter_dt *dtp, int done)
 void
 next_record (st_parameter_dt *dtp, int done)
 {
+  if (is_stream_io (dtp))
+    return;
+
   gfc_offset fp; /* File position.  */
 
   dtp->u.p.current_unit->read_bad = 0;
@@ -2177,7 +2292,6 @@ next_record (st_parameter_dt *dtp, int done)
 
   /* keep position up to date for INQUIRE */
   dtp->u.p.current_unit->flags.position = POSITION_ASIS;
-
   dtp->u.p.current_unit->current_record = 0;
   if (dtp->u.p.current_unit->flags.access == ACCESS_DIRECT)
    {
@@ -2238,7 +2352,7 @@ finalize_transfer (st_parameter_dt *dtp)
 
   if ((cf & IOPARM_DT_LIST_FORMAT) != 0 && dtp->u.p.mode == READING)
     finish_list_read (dtp);
-  else
+  else if (!is_stream_io (dtp))
     {
       dtp->u.p.current_unit->current_record = 0;
       if (dtp->u.p.advance_status == ADVANCE_NO || dtp->u.p.seen_dollar)
@@ -2250,9 +2364,13 @@ finalize_transfer (st_parameter_dt *dtp)
          dtp->u.p.seen_dollar = 0;
          return;
        }
-
       next_record (dtp, 1);
     }
+  else
+    {
+      flush (dtp->u.p.current_unit->s);
+      dtp->u.p.current_unit->last_record = dtp->rec;
+    }
 
   sfree (dtp->u.p.current_unit->s);
 }
@@ -2325,7 +2443,6 @@ export_proto(st_read);
 void
 st_read (st_parameter_dt *dtp)
 {
-
   library_start (&dtp->common);
 
   data_transfer_init (dtp, 1);