OSDN Git Service

* config/os/irix/irix6.5/os_defines.h (_GLIBCXX_FIONREAD_TAKES_OFF_T):
[pf3gnuchains/gcc-fork.git] / libstdc++-v3 / config / io / basic_file_stdio.cc
index 7f4c909..8cba0db 100644 (file)
@@ -1,6 +1,6 @@
 // Wrapper of C-language FILE struct -*- C++ -*-
 
-// Copyright (C) 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+// Copyright (C) 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
 //
 // This file is part of the GNU ISO C++ Library.  This library is free
 // software; you can redistribute it and/or modify it under the
 
 #include <bits/basic_file.h>
 #include <fcntl.h>
-#include <unistd.h>
 #include <errno.h>
 
+#ifdef _GLIBCXX_HAVE_POLL
+#include <poll.h>
+#endif
+
+// Pick up ioctl on Solaris 2.8
+#ifdef _GLIBCXX_HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+// Pick up FIONREAD on Solaris 2
+#ifdef _GLIBCXX_HAVE_SYS_IOCTL_H
+#define BSD_COMP 
+#include <sys/ioctl.h>
+#endif
+
+// Pick up FIONREAD on Solaris 2.5.
+#ifdef _GLIBCXX_HAVE_SYS_FILIO_H
+#include <sys/filio.h>
+#endif
+
+#ifdef _GLIBCXX_HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#endif
+
+#if defined(_GLIBCXX_HAVE_S_ISREG) || defined(_GLIBCXX_HAVE_S_IFREG)
+# include <sys/stat.h>
+# ifdef _GLIBCXX_HAVE_S_ISREG
+#  define _GLIBCXX_ISREG(x) S_ISREG(x)
+# else
+#  define _GLIBCXX_ISREG(x) (((x) & S_IFMT) == S_IFREG)
+# endif
+#endif
+
+#include <limits> // For <off_t>::max() and min()
+
+namespace __gnu_internal
+{
+  // Map ios_base::openmode flags to a string for use in fopen().
+  // Table of valid combinations as given in [lib.filebuf.members]/2.
+  static const char*
+  fopen_mode(std::ios_base::openmode mode)
+  {
+    enum 
+      {
+       in     = std::ios_base::in,
+       out    = std::ios_base::out,
+       trunc  = std::ios_base::trunc,
+       app    = std::ios_base::app,
+       binary = std::ios_base::binary
+      };
+    
+    switch (mode & (in|out|trunc|app|binary))
+      {
+      case (   out                 ): return "w";  
+      case (   out      |app       ): return "a";  
+      case (   out|trunc           ): return "w";  
+      case (in                     ): return "r";  
+      case (in|out                 ): return "r+"; 
+      case (in|out|trunc           ): return "w+"; 
+       
+      case (   out          |binary): return "wb"; 
+      case (   out      |app|binary): return "ab"; 
+      case (   out|trunc    |binary): return "wb"; 
+      case (in              |binary): return "rb"; 
+      case (in|out          |binary): return "r+b";
+      case (in|out|trunc    |binary): return "w+b";
+       
+      default: return 0; // invalid
+      }
+  }
+} // namespace __gnu_internal
+
 namespace std 
 {
   // Definitions for __basic_file<char>.
@@ -45,57 +116,6 @@ namespace std
   __basic_file<char>::~__basic_file()
   { this->close(); }
       
-  void 
-  __basic_file<char>::_M_open_mode(ios_base::openmode __mode, int& __p_mode, 
-                                  int&, char* __c_mode)
-  {  
-    bool __testb = __mode & ios_base::binary;
-    bool __testi = __mode & ios_base::in;
-    bool __testo = __mode & ios_base::out;
-    bool __testt = __mode & ios_base::trunc;
-    bool __testa = __mode & ios_base::app;
-      
-    // Set __c_mode for use in fopen.
-    // Set __p_mode for use in open.
-    if (!__testi && __testo && !__testt && !__testa)
-      {
-       strcpy(__c_mode, "w");
-       __p_mode = (O_WRONLY | O_CREAT);
-      }
-    if (!__testi && __testo && !__testt && __testa)
-      {
-       strcpy(__c_mode, "a");
-       __p_mode |=  O_WRONLY | O_CREAT | O_APPEND;
-      }
-    if (!__testi && __testo && __testt && !__testa)
-      {
-       strcpy(__c_mode, "w");
-       __p_mode |=  O_WRONLY | O_CREAT | O_TRUNC;
-      }
-
-    if (__testi && !__testo && !__testt && !__testa)
-      {
-       strcpy(__c_mode, "r");
-#if defined (O_NONBLOCK)
-       __p_mode |=  O_RDONLY | O_NONBLOCK;
-#else
-       __p_mode |=  O_RDONLY;
-#endif
-      }
-    if (__testi && __testo && !__testt && !__testa)
-      {
-       strcpy(__c_mode, "r+");
-       __p_mode |=  O_RDWR | O_CREAT;
-      }
-    if (__testi && __testo && __testt && !__testa)
-      {
-       strcpy(__c_mode, "w+");
-       __p_mode |=  O_RDWR | O_CREAT | O_TRUNC;
-      }
-    if (__testb)
-      strcat(__c_mode, "b");
-  }
-  
   __basic_file<char>*
   __basic_file<char>::sys_open(__c_file* __file, ios_base::openmode) 
   {
@@ -104,65 +124,43 @@ namespace std
       {
        _M_cfile = __file;
        _M_cfile_created = false;
+       this->sync();
        __ret = this;
       }
     return __ret;
   }
   
   __basic_file<char>*
-  __basic_file<char>::sys_open(int __fd, ios_base::openmode __mode, 
-                              bool __del) 
+  __basic_file<char>::sys_open(int __fd, ios_base::openmode __mode)
   {
     __basic_file* __ret = NULL;
-    int __p_mode = 0;
-    int __rw_mode = 0;
-    char __c_mode[4];
-    
-    _M_open_mode(__mode, __p_mode, __rw_mode, __c_mode);
-    if (!this->is_open() && (_M_cfile = fdopen(__fd, __c_mode)))
+    const char* __c_mode = __gnu_internal::fopen_mode(__mode);
+    if (__c_mode && !this->is_open() 
+       && (_M_cfile = fdopen(__fd, __c_mode)))
       {
-       // Iff __del is true, then close will fclose the fd.
-       _M_cfile_created = __del;
-
+       _M_cfile_created = true;
        if (__fd == 0)
          setvbuf(_M_cfile, reinterpret_cast<char*>(NULL), _IONBF, 0);
-
        __ret = this;
       }
     return __ret;
   }
-
-  int
-  __basic_file<char>::sys_getc() 
-  { return getc(_M_cfile); }
-
-  int
-  __basic_file<char>::sys_ungetc(int __c) 
-  { return ungetc(__c, _M_cfile); }
   
   __basic_file<char>* 
   __basic_file<char>::open(const char* __name, ios_base::openmode __mode, 
                           int /*__prot*/)
   {
     __basic_file* __ret = NULL;
-    int __p_mode = 0;
-    int __rw_mode = 0;
-    char __c_mode[4];
-      
-    _M_open_mode(__mode, __p_mode, __rw_mode, __c_mode);
-
-    if (!this->is_open())
+    const char* __c_mode = __gnu_internal::fopen_mode(__mode);
+    if (__c_mode && !this->is_open())
       {
+#ifdef _GLIBCXX_USE_LFS
+       if ((_M_cfile = fopen64(__name, __c_mode)))
+#else
        if ((_M_cfile = fopen(__name, __c_mode)))
+#endif
          {
            _M_cfile_created = true;
-
-#if defined (F_SETFL) && defined (O_NONBLOCK)
-           // Set input to nonblocking for fifos.
-           if (__mode & ios_base::in)
-             fcntl(this->fd(), F_SETFL, O_NONBLOCK);
-#endif
-
            __ret = this;
          }
       }
@@ -180,85 +178,121 @@ namespace std
   __basic_file<char>* 
   __basic_file<char>::close()
   { 
-    __basic_file* __retval = static_cast<__basic_file*>(NULL);
+    __basic_file* __ret = static_cast<__basic_file*>(NULL);
     if (this->is_open())
       {
-       fflush(_M_cfile);
-       if ((_M_cfile_created && fclose(_M_cfile) == 0) || !_M_cfile_created)
-         {
-           _M_cfile = 0;
-           __retval = this;
-         }
+       if (_M_cfile_created)
+         fclose(_M_cfile);
+       else
+         this->sync();
+       _M_cfile = 0;
+       __ret = this;
       }
-    return __retval;
+    return __ret;
   }
  
-  // In the next four functions we want to use stdio functions only
-  // when synced with stdio (_M_buf_size == 1): I/O primitives do not
-  // block until the asked number of bytes are available.
   streamsize 
-  __basic_file<char>::xsgetn(char* __s, streamsize __n, bool __stdio)
+  __basic_file<char>::xsgetn(char* __s, streamsize __n)
   {
-    if (__stdio)
-      return fread(__s, 1, __n, _M_cfile);
-    else
-      {
-       streamsize __ret;
-        do
-         __ret = read(this->fd(), __s, __n);
-       while (__ret == -1L && errno == EINTR);
-       return __ret;
-      }
+    streamsize __ret;
+    do
+      __ret = read(this->fd(), __s, __n);
+    while (__ret == -1L && errno == EINTR);
+    return __ret;
   }
     
   streamsize 
-  __basic_file<char>::xsputn(const char* __s, streamsize __n, bool __stdio)
+  __basic_file<char>::xsputn(const char* __s, streamsize __n)
   {
-    if (__stdio)
-      return fwrite(__s, 1, __n, _M_cfile);
-    else
-      {
-       streamsize __ret;
-        do
-         __ret = write(this->fd(), __s, __n);
-       while (__ret == -1L && errno == EINTR);
-       return __ret;
-      }
+    streamsize __ret;
+    do
+      __ret = write(this->fd(), __s, __n);
+    while (__ret == -1L && errno == EINTR);
+    return __ret;
   }
-  
-  streamoff
-  __basic_file<char>::seekoff(streamoff __off, ios_base::seekdir __way, 
-                             bool __stdio, ios_base::openmode /*__mode*/)
-  { 
-    if (!__stdio)
-      return lseek(this->fd(), __off, __way);
-    else
+
+  streamsize 
+  __basic_file<char>::xsputn_2(const char* __s1, streamsize __n1,
+                              const char* __s2, streamsize __n2)
+  {
+    streamsize __ret = 0;
+#ifdef _GLIBCXX_HAVE_WRITEV
+    struct iovec __iov[2];
+    __iov[0].iov_base = const_cast<char*>(__s1);
+    __iov[0].iov_len = __n1;
+    __iov[1].iov_base = const_cast<char*>(__s2);
+    __iov[1].iov_len = __n2;
+
+    do
+      __ret = writev(this->fd(), __iov, 2);
+    while (__ret == -1L && errno == EINTR);
+#else
+    if (__n1)
+      do
+       __ret = write(this->fd(), __s1, __n1);
+      while (__ret == -1L && errno == EINTR);
+
+    if (__ret == __n1)
       {
-       if (!fseek(_M_cfile, __off, __way))
-         return ftell(_M_cfile); 
-       else
-         // Fseek failed.
-         return -1L;
+       do
+         __ret = write(this->fd(), __s2, __n2);
+       while (__ret == -1L && errno == EINTR);
+       
+       if (__ret != -1L)
+         __ret += __n1;
       }
+#endif
+    return __ret;
   }
 
   streamoff
-  __basic_file<char>::seekpos(streamoff __pos, bool __stdio,
-                             ios_base::openmode /*__mode*/)
-  { 
-    if (!__stdio)
-      return lseek(this->fd(), __pos, ios_base::beg);
-    else
-      {
-       if (!fseek(_M_cfile, __pos, ios_base::beg))
-         return ftell(_M_cfile);
-       else
-         // Fseek failed.
-         return -1L;
-      }
+  __basic_file<char>::seekoff(streamoff __off, ios_base::seekdir __way)
+  {
+#ifdef _GLIBCXX_USE_LFS
+    return lseek64(this->fd(), __off, __way);
+#else
+    if (__off > std::numeric_limits<off_t>::max()
+       || __off < std::numeric_limits<off_t>::min())
+      return -1L;
+    return lseek(this->fd(), __off, __way);
+#endif
   }
-  
+
   int 
   __basic_file<char>::sync() 
   { return fflush(_M_cfile); }
+
+  streamsize
+  __basic_file<char>::showmanyc()
+  {
+#ifdef FIONREAD
+    // Pipes and sockets.    
+#ifdef _GLIBCXX_FIONREAD_TAKES_OFF_T
+    off_t __num = 0;
+#else
+    int __num = 0;
+#endif
+    int __r = ioctl(this->fd(), FIONREAD, &__num);
+    if (!__r && __num >= 0)
+      return __num; 
+#endif    
+
+#ifdef _GLIBCXX_HAVE_POLL
+    // Cheap test.
+    struct pollfd __pfd[1];
+    __pfd[0].fd = this->fd();
+    __pfd[0].events = POLLIN;
+    if (poll(__pfd, 1, 0) <= 0)
+      return 0;
+#endif   
+
+#if defined(_GLIBCXX_HAVE_S_ISREG) || defined(_GLIBCXX_HAVE_S_IFREG)
+    // Regular files.
+    struct stat __buffer;
+    int __ret = fstat(this->fd(), &__buffer);
+    if (!__ret && _GLIBCXX_ISREG(__buffer.st_mode))
+       return __buffer.st_size - lseek(this->fd(), 0, ios_base::cur);
+#endif
+    return 0;
+  }
 }  // namespace std