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 */ 124 int 125 printf (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 */ 139 int 140 fprintf (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 */ 154 int 155 vprintf (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 */ 162 int 163 vfprintf (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 170 int 171 putchar (int c) 172 { 173 return fputc (c, stdout); 174 } 175 176 int 177 fputc (int c, FILE *stream) 178 #undef fputc 179 { 180 CALL_WITH_SIGPIPE_EMULATION (int, fputc (c, stream), ret == EOF) 181 } 182 183 int 184 fputs (const char *string, FILE *stream) 185 #undef fputs 186 { 187 CALL_WITH_SIGPIPE_EMULATION (int, fputs (string, stream), ret == EOF) 188 } 189 190 int 191 puts (const char *string) 192 #undef puts 193 { 194 FILE *stream = stdout; 195 CALL_WITH_SIGPIPE_EMULATION (int, puts (string), ret == EOF) 196 } 197 198 size_t 199 fwrite (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