1
0
mirror of https://https.git.savannah.gnu.org/git/gnulib.git synced 2026-04-28 14:43:36 +00:00
Files
gnulib/lib/write.c
Bruno Haible 03c3f38b55 Implement a way to opt out from MSVC support.
This is useful for Emacs.

* modules/msvc-nothrow (configure.ac): Invoke gl_MODULE_INDICATOR.
* lib/accept4.c: Include <io.h> as an alternative to msvc-nothrow.h.
* lib/error.c: Likewise.
* lib/fcntl.c: Likewise.
* lib/flock.c: Likewise.
* lib/fstat.c: Likewise.
* lib/fsync.c: Likewise.
* lib/ioctl.c: Likewise.
* lib/isapipe.c: Likewise.
* lib/lseek.c: Likewise.
* lib/nonblocking.c: Likewise.
* lib/poll.c: Likewise.
* lib/select.c: Likewise.
* lib/sockets.h: Likewise.
* lib/sockets.c: Likewise.
* lib/stdio-read.c: Likewise.
* lib/stdio-write.c: Likewise.
* lib/utimens.c: Likewise.
* lib/w32sock.h: Likewise.
* lib/w32spawn.h: Likewise.
* tests/test-cloexec.c: Likewise.
* tests/test-dup-safer.c: Likewise.
* tests/test-dup2.c: Likewise.
* tests/test-dup3.c: Likewise.
* tests/test-fcntl.c: Likewise.
* tests/test-pipe.c: Likewise.
* tests/test-pipe2.c: Likewise.
* lib/ftruncate.c: Likewise.
(chsize_nothrow): Renamed from chsize.
* lib/msvc-nothrow.c: Don't include msvc-inval.h if
HAVE_MSVC_INVALID_PARAMETER_HANDLER is not defined.
* lib/close.c: Likewise.
* lib/dup.c: Likewise.
* lib/fclose.c: Likewise.
* lib/raise.c: Likewise.
* tests/test-fgetc.c: Likewise.
* tests/test-fputc.c: Likewise.
* tests/test-fread.c: Likewise.
* tests/test-fwrite.c: Likewise.
* lib/getdtablesize.c: Likewise.
(_setmaxstdio_nothrow): Renamed from _setmaxstdio.
* lib/isatty.c: Don't include msvc-inval.h if
HAVE_MSVC_INVALID_PARAMETER_HANDLER is not defined.
Include <io.h> as an alternative to msvc-nothrow.h.
* lib/read.c: Likewise.
* lib/write.c: Likewise.
* lib/dup2.c: Likewise.
(dup2_nothrow): New function.
(ms_windows_dup2): Use it.
* m4/close.m4 (gl_FUNC_CLOSE): Invoke gl_MSVC_INVAL and test
HAVE_MSVC_INVALID_PARAMETER_HANDLER only if gl_MSVC_INVAL is defined.
* m4/dup.m4 (gl_FUNC_DUP): Likewise.
* m4/fdopen.m4 (gl_FUNC_FDOPEN): Likewise.
* m4/raise.m4 (gl_FUNC_RAISE): Likewise.
* m4/read.m4 (gl_FUNC_READ): Likewise.
* m4/write.m4 (gl_FUNC_WRITE): Likewise.
* doc/windows-without-msvc.texi: New file.
* doc/gnulib.texi (Native Windows Support without MSVC Support): New
section.
2017-05-10 22:18:34 +02:00

152 lines
5.1 KiB
C

/* POSIX compatible write() function.
Copyright (C) 2008-2017 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 <http://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 __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