text: /* POSIX compatible write() function.
     Copyright (C) 2008-2018 Free Software Foundation, Inc.
     Written by Bruno Haible <bruno@clisp.org>, 2008.
  
     This program 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 3 of the License, or
     (at your option) any later version.
  
     This program 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 this program.  If not, see <https://www.gnu.org/licenses/>.  */
  
  #include <config.h>
  
  /* Specification.  */
  #include <unistd.h>
  
  /* On native Windows platforms, SIGPIPE does not exist.  When write() is
     called on a pipe with no readers, WriteFile() fails with error
     GetLastError() = ERROR_NO_DATA, and write() in consequence fails with
     error EINVAL.  */
  
  #if defined _WIN32 && ! defined __CYGWIN__
  
  # include <errno.h>
  # include <signal.h>
  # include <io.h>
  
  # define WIN32_LEAN_AND_MEAN  /* avoid including junk */
  # include <windows.h>
  
  # if HAVE_MSVC_INVALID_PARAMETER_HANDLER
  #  include "msvc-inval.h"
  # endif
  # if GNULIB_MSVC_NOTHROW
  #  include "msvc-nothrow.h"
  # else
  #  include <io.h>
  # endif
  
  # undef write
  
  # if HAVE_MSVC_INVALID_PARAMETER_HANDLER
  static ssize_t
  write_nothrow (int fd, const void *buf, size_t count)
  {
    ssize_t result;
  
    TRY_MSVC_INVAL
      {
        result = write (fd, buf, count);
      }
    CATCH_MSVC_INVAL
      {
        result = -1;
        errno = EBADF;
      }
    DONE_MSVC_INVAL;
  
    return result;
  }
  # else
  #  define write_nothrow write
  # endif
  
  ssize_t
  rpl_write (int fd, const void *buf, size_t count)
  {
    for (;;)
      {
        ssize_t ret = write_nothrow (fd, buf, count);
  
        if (ret < 0)
          {
  # if GNULIB_NONBLOCKING
            if (errno == ENOSPC)
              {
                HANDLE h = (HANDLE) _get_osfhandle (fd);
                if (GetFileType (h) == FILE_TYPE_PIPE)
                  {
                    /* h is a pipe or socket.  */
                    DWORD state;
                    if (GetNamedPipeHandleState (h, &state, NULL, NULL, NULL,
                                                 NULL, 0)
                        && (state & PIPE_NOWAIT) != 0)
                      {
                        /* h is a pipe in non-blocking mode.
                           We can get here in four situations:
                             1. When the pipe buffer is full.
                             2. When count <= pipe_buf_size and the number of
                                free bytes in the pipe buffer is < count.
                             3. When count > pipe_buf_size and the number of free
                                bytes in the pipe buffer is > 0, < pipe_buf_size.
                             4. When count > pipe_buf_size and the pipe buffer is
                                entirely empty.
                           The cases 1 and 2 are POSIX compliant.  In cases 3 and
                           4 POSIX specifies that write() must split the request
                           and succeed with a partial write.  We fix case 4.
                           We don't fix case 3 because it is not essential for
                           programs.  */
                        DWORD out_size; /* size of the buffer for outgoing data */
                        DWORD in_size;  /* size of the buffer for incoming data */
                        if (GetNamedPipeInfo (h, NULL, &out_size, &in_size, NULL))
                          {
                            size_t reduced_count = count;
                            /* In theory we need only one of out_size, in_size.
                               But I don't know which of the two.  The description
                               is ambiguous.  */
                            if (out_size != 0 && out_size < reduced_count)
                              reduced_count = out_size;
                            if (in_size != 0 && in_size < reduced_count)
                              reduced_count = in_size;
                            if (reduced_count < count)
                              {
                                /* Attempt to write only the first part.  */
                                count = reduced_count;
                                continue;
                              }
                          }
                        /* Change errno from ENOSPC to EAGAIN.  */
                        errno = EAGAIN;
                      }
                  }
              }
            else
  # endif
              {
  # if GNULIB_SIGPIPE
                if (GetLastError () == ERROR_NO_DATA
                    && GetFileType ((HANDLE) _get_osfhandle (fd))
                       == FILE_TYPE_PIPE)
                  {
                    /* Try to raise signal SIGPIPE.  */
                    raise (SIGPIPE);
                    /* If it is currently blocked or ignored, change errno from
                       EINVAL to EPIPE.  */
                    errno = EPIPE;
                  }
  # endif
              }
          }
        return ret;
      }
  }
  
  #endif
  