| 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 | 
|---|