1/* POSIX compatible FILE stream write function. 2 Copyright (C) 2008-2022 Free Software Foundation, Inc. 3 Written by Bruno Haible <bruno@clisp.org>, 2008. 4 5 This file is free software: you can redistribute it and/or modify 6 it under the terms of the GNU Lesser General Public License as 7 published by the Free Software Foundation; either version 2.1 of the 8 License, or (at your option) any later version. 9 10 This file is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU Lesser General Public License for more details. 14 15 You should have received a copy of the GNU Lesser General Public License 16 along with this program. If not, see <https://www.gnu.org/licenses/>. */ 17 18#include <config.h> 19 20/* Specification. */ 21#include <stdio.h> 22 23/* Replace these functions only if module 'nonblocking' or module 'sigpipe' is 24 requested. */ 25#if GNULIB_NONBLOCKING || GNULIB_SIGPIPE 26 27/* On native Windows platforms, SIGPIPE does not exist. When write() is 28 called on a pipe with no readers, WriteFile() fails with error 29 GetLastError() = ERROR_NO_DATA, and write() in consequence fails with 30 error EINVAL. This write() function is at the basis of the function 31 which flushes the buffer of a FILE stream. */ 32 33# if defined _WIN32 && ! defined __CYGWIN__ 34 35# include <errno.h> 36# include <signal.h> 37# include <io.h> 38 39# define WIN32_LEAN_AND_MEAN /* avoid including junk */ 40# include <windows.h> 41 42# if GNULIB_MSVC_NOTHROW 43# include "msvc-nothrow.h" 44# else 45# include <io.h> 46# endif 47 48/* Don't assume that UNICODE is not defined. */ 49# undef GetNamedPipeHandleState 50# define GetNamedPipeHandleState GetNamedPipeHandleStateA 51 52# if GNULIB_NONBLOCKING 53# define CLEAR_ERRNO \ 54 errno = 0; 55# define HANDLE_ENOSPC \ 56 if (errno == ENOSPC && ferror (stream)) \ 57 { \ 58 int fd = fileno (stream); \ 59 if (fd >= 0) \ 60 { \ 61 HANDLE h = (HANDLE) _get_osfhandle (fd); \ 62 if (GetFileType (h) == FILE_TYPE_PIPE) \ 63 { \ 64 /* h is a pipe or socket. */ \ 65 DWORD state; \ 66 if (GetNamedPipeHandleState (h, &state, NULL, NULL, \ 67 NULL, NULL, 0) \ 68 && (state & PIPE_NOWAIT) != 0) \ 69 /* h is a pipe in non-blocking mode. \ 70 Change errno from ENOSPC to EAGAIN. */ \ 71 errno = EAGAIN; \ 72 } \ 73 } \ 74 } \ 75 else 76# else 77# define CLEAR_ERRNO 78# define HANDLE_ENOSPC 79# endif 80 81# if GNULIB_SIGPIPE 82# define CLEAR_LastError \ 83 SetLastError (0); 84# define HANDLE_ERROR_NO_DATA \ 85 if (GetLastError () == ERROR_NO_DATA && ferror (stream)) \ 86 { \ 87 int fd = fileno (stream); \ 88 if (fd >= 0 \ 89 && GetFileType ((HANDLE) _get_osfhandle (fd)) \ 90 == FILE_TYPE_PIPE) \ 91 { \ 92 /* Try to raise signal SIGPIPE. */ \ 93 raise (SIGPIPE); \ 94 /* If it is currently blocked or ignored, change errno from \ 95 EINVAL to EPIPE. */ \ 96 errno = EPIPE; \ 97 } \ 98 } \ 99 else 100# else 101# define CLEAR_LastError 102# define HANDLE_ERROR_NO_DATA 103# endif 104 105# define CALL_WITH_SIGPIPE_EMULATION(RETTYPE, EXPRESSION, FAILED) \ 106 if (ferror (stream)) \ 107 return (EXPRESSION); \ 108 else \ 109 { \ 110 RETTYPE ret; \ 111 CLEAR_ERRNO \ 112 CLEAR_LastError \ 113 ret = (EXPRESSION); \ 114 if (FAILED) \ 115 { \ 116 HANDLE_ENOSPC \ 117 HANDLE_ERROR_NO_DATA \ 118 ; \ 119 } \ 120 return ret; \ 121 } 122 123# if !REPLACE_PRINTF_POSIX /* avoid collision with printf.c */ 124int 125printf (const char *format, ...) 126{ 127 int retval; 128 va_list args; 129 130 va_start (args, format); 131 retval = vfprintf (stdout, format, args); 132 va_end (args); 133 134 return retval; 135} 136# endif 137 138# if !REPLACE_FPRINTF_POSIX /* avoid collision with fprintf.c */ 139int 140fprintf (FILE *stream, const char *format, ...) 141{ 142 int retval; 143 va_list args; 144 145 va_start (args, format); 146 retval = vfprintf (stream, format, args); 147 va_end (args); 148 149 return retval; 150} 151# endif 152 153# if !REPLACE_VPRINTF_POSIX /* avoid collision with vprintf.c */ 154int 155vprintf (const char *format, va_list args) 156{ 157 return vfprintf (stdout, format, args); 158} 159# endif 160 161# if !REPLACE_VFPRINTF_POSIX /* avoid collision with vfprintf.c */ 162int 163vfprintf (FILE *stream, const char *format, va_list args) 164#undef vfprintf 165{ 166 CALL_WITH_SIGPIPE_EMULATION (int, vfprintf (stream, format, args), ret == EOF) 167} 168# endif 169 170int 171putchar (int c) 172{ 173 return fputc (c, stdout); 174} 175 176int 177fputc (int c, FILE *stream) 178#undef fputc 179{ 180 CALL_WITH_SIGPIPE_EMULATION (int, fputc (c, stream), ret == EOF) 181} 182 183int 184fputs (const char *string, FILE *stream) 185#undef fputs 186{ 187 CALL_WITH_SIGPIPE_EMULATION (int, fputs (string, stream), ret == EOF) 188} 189 190int 191puts (const char *string) 192#undef puts 193{ 194 FILE *stream = stdout; 195 CALL_WITH_SIGPIPE_EMULATION (int, puts (string), ret == EOF) 196} 197 198size_t 199fwrite (const void *ptr, size_t s, size_t n, FILE *stream) 200#undef fwrite 201{ 202 CALL_WITH_SIGPIPE_EMULATION (size_t, fwrite (ptr, s, n, stream), ret < n) 203} 204 205# endif 206#endif 207