OSDN Git Service

PR libfortran/21185
[pf3gnuchains/gcc-fork.git] / libgfortran / io / unix.c
index ded0d05..6cb578f 100644 (file)
@@ -30,13 +30,11 @@ Boston, MA 02110-1301, USA.  */
 
 /* Unix stream I/O module */
 
-#include "config.h"
+#include "io.h"
 #include <stdlib.h>
 #include <limits.h>
 
 #include <unistd.h>
-#include <stdio.h>
-#include <stdarg.h>
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <assert.h>
@@ -44,9 +42,6 @@ Boston, MA 02110-1301, USA.  */
 #include <string.h>
 #include <errno.h>
 
-#include "libgfortran.h"
-#include "io.h"
-
 #ifndef SSIZE_MAX
 #define SSIZE_MAX SHRT_MAX
 #endif
@@ -142,10 +137,6 @@ typedef struct
 }
 int_stream;
 
-extern stream *init_error_stream (unix_stream *);
-internal_proto(init_error_stream);
-
-
 /* This implementation of stream I/O is based on the paper:
  *
  *  "Exploiting the advantages of mapped files for stream I/O",
@@ -220,13 +211,13 @@ move_pos_offset (stream* st, int pos_off)
 static int
 fix_fd (int fd)
 {
+#ifdef HAVE_DUP
   int input, output, error;
 
   input = output = error = 0;
 
   /* Unix allocates the lowest descriptors first, so a loop is not
      required, but this order is. */
-
   if (fd == STDIN_FILENO)
     {
       fd = dup (fd);
@@ -249,6 +240,7 @@ fix_fd (int fd)
     close (STDOUT_FILENO);
   if (error)
     close (STDERR_FILENO);
+#endif
 
   return fd;
 }
@@ -837,7 +829,7 @@ fd_open (unix_stream * s)
   s->st.sfree = (void *) fd_sfree;
   s->st.close = (void *) fd_close;
   s->st.seek = (void *) fd_seek;
-  s->st.truncate = (void *) fd_truncate;
+  s->st.trunc = (void *) fd_truncate;
   s->st.read = (void *) fd_read;
   s->st.write = (void *) fd_write;
   s->st.set = (void *) fd_sset;
@@ -1051,7 +1043,7 @@ open_internal (char *base, int length)
   s->st.sfree = (void *) mem_sfree;
   s->st.close = (void *) mem_close;
   s->st.seek = (void *) mem_seek;
-  s->st.truncate = (void *) mem_truncate;
+  s->st.trunc = (void *) mem_truncate;
   s->st.read = (void *) mem_read;
   s->st.write = (void *) mem_write;
   s->st.set = (void *) mem_set;
@@ -1155,7 +1147,7 @@ tempfile (st_parameter_open *opp)
 
   template = get_mem (strlen (tempdir) + 20);
 
-  st_sprintf (template, "%s/gfortrantmpXXXXXX", tempdir);
+  sprintf (template, "%s/gfortrantmpXXXXXX", tempdir);
 
 #ifdef HAVE_MKSTEMP
 
@@ -1385,122 +1377,59 @@ error_stream (void)
   return fd_to_stream (STDERR_FILENO, PROT_WRITE);
 }
 
-/* init_error_stream()-- Return a pointer to the error stream.  This
- * subroutine is called when the stream is needed, rather than at
- * initialization.  We want to work even if memory has been seriously
- * corrupted. */
 
-stream *
-init_error_stream (unix_stream *error)
-{
-  memset (error, '\0', sizeof (*error));
-
-  error->fd = options.use_stderr ? STDERR_FILENO : STDOUT_FILENO;
+/* st_vprintf()-- vprintf function for error output.  To avoid buffer
+   overruns, we limit the length of the buffer to ST_VPRINTF_SIZE.  2k
+   is big enough to completely fill a 80x25 terminal, so it shuld be
+   OK.  We use a direct write() because it is simpler and least likely
+   to be clobbered by memory corruption.  Writing an error message
+   longer than that is an error.  */
 
-  error->st.alloc_w_at = (void *) fd_alloc_w_at;
-  error->st.sfree = (void *) fd_sfree;
-
-  error->unbuffered = 1;
-  error->buffer = error->small_buffer;
-
-  return (stream *) error;
-}
-
-/* st_printf()-- simple printf() function for streams that handles the
- * formats %d, %s and %c.  This function handles printing of error
- * messages that originate within the library itself, not from a user
- * program. */
+#define ST_VPRINTF_SIZE 2048
 
 int
-st_printf (const char *format, ...)
+st_vprintf (const char *format, va_list ap)
 {
-  int count, total;
-  va_list arg;
-  char *p;
-  const char *q;
-  stream *s;
-  char itoa_buf[GFC_ITOA_BUF_SIZE];
-  unix_stream err_stream;
+  static char buffer[ST_VPRINTF_SIZE];
+  int written;
+  int fd;
 
-  total = 0;
-  s = init_error_stream (&err_stream);
-  va_start (arg, format);
+  fd = options.use_stderr ? STDERR_FILENO : STDOUT_FILENO;
+#ifdef HAVE_VSNPRINTF
+  written = vsnprintf(buffer, ST_VPRINTF_SIZE, format, ap);
+#else
+  written = vsprintf(buffer, format, ap);
 
-  for (;;)
+  if (written >= ST_VPRINTF_SIZE-1)
     {
-      count = 0;
-
-      while (format[count] != '%' && format[count] != '\0')
-       count++;
-
-      if (count != 0)
-       {
-         p = salloc_w (s, &count);
-         memmove (p, format, count);
-         sfree (s);
-       }
+      /* The error message was longer than our buffer.  Ouch.  Because
+        we may have messed up things badly, report the error and
+        quit.  */
+#define ERROR_MESSAGE "Internal error: buffer overrun in st_vprintf()\n"
+      write (fd, buffer, ST_VPRINTF_SIZE-1);
+      write (fd, ERROR_MESSAGE, strlen(ERROR_MESSAGE));
+      sys_exit(2);
+#undef ERROR_MESSAGE
 
-      total += count;
-      format += count;
-      if (*format++ == '\0')
-       break;
+    }
+#endif
 
-      switch (*format)
-       {
-       case 'c':
-         count = 1;
-
-         p = salloc_w (s, &count);
-         *p = (char) va_arg (arg, int);
-
-         sfree (s);
-         break;
-
-       case 'd':
-         q = gfc_itoa (va_arg (arg, int), itoa_buf, sizeof (itoa_buf));
-         count = strlen (q);
-
-         p = salloc_w (s, &count);
-         memmove (p, q, count);
-         sfree (s);
-         break;
-
-       case 'x':
-         q = xtoa (va_arg (arg, unsigned), itoa_buf, sizeof (itoa_buf));
-         count = strlen (q);
-
-         p = salloc_w (s, &count);
-         memmove (p, q, count);
-         sfree (s);
-         break;
-
-       case 's':
-         q = va_arg (arg, char *);
-         count = strlen (q);
-
-         p = salloc_w (s, &count);
-         memmove (p, q, count);
-         sfree (s);
-         break;
-
-       case '\0':
-         return total;
-
-       default:
-         count = 2;
-         p = salloc_w (s, &count);
-         p[0] = format[-1];
-         p[1] = format[0];
-         sfree (s);
-         break;
-       }
+  written = write (fd, buffer, written);
+  return written;
+}
 
-      total += count;
-      format++;
-    }
+/* st_printf()-- printf() function for error output.  This just calls
+   st_vprintf() to do the actual work.  */
 
-  va_end (arg);
-  return total;
+int
+st_printf (const char *format, ...)
+{
+  int written;
+  va_list ap;
+  va_start (ap, format);
+  written = st_vprintf(format, ap);
+  va_end (ap);
+  return written;
 }
 
 
@@ -1847,6 +1776,36 @@ inquire_unformatted (const char *string, int len)
 }
 
 
+#ifndef HAVE_ACCESS
+
+#ifndef W_OK
+#define W_OK 2
+#endif
+
+#ifndef R_OK
+#define R_OK 4
+#endif
+
+/* Fallback implementation of access() on systems that don't have it.
+   Only modes R_OK and W_OK are used in this file.  */
+
+static int
+fallback_access (const char *path, int mode)
+{
+  if ((mode & R_OK) && open (path, O_RDONLY) < 0)
+    return -1;
+
+  if ((mode & W_OK) && open (path, O_WRONLY) < 0)
+    return -1;
+
+  return 0;
+}
+
+#undef access
+#define access fallback_access
+#endif
+
+
 /* inquire_access()-- Given a fortran string, determine if the file is
  * suitable for access. */
 
@@ -1945,7 +1904,7 @@ stream_isatty (stream *s)
 }
 
 char *
-stream_ttyname (stream *s)
+stream_ttyname (stream *s __attribute__ ((unused)))
 {
 #ifdef HAVE_TTYNAME
   return ttyname (((unix_stream *) s)->fd);