1/* POSIX compatible FILE stream write function.
2   Copyright (C) 2008-2011 Free Software Foundation, Inc.
3   Written by Bruno Haible <bruno@clisp.org>, 2008.
4
5   This program is free software: you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published by
7   the Free Software Foundation; either version 3 of the License, or
8   (at your option) any later version.
9
10   This program 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 General Public License for more details.
14
15   You should have received a copy of the GNU General Public License
16   along with this program.  If not, see <http://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 __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_NONBLOCKING
43#   define CLEAR_ERRNO \
44      errno = 0;
45#   define HANDLE_ENOSPC \
46          if (errno == ENOSPC && ferror (stream))                             \
47            {                                                                 \
48              int fd = fileno (stream);                                       \
49              if (fd >= 0)                                                    \
50                {                                                             \
51                  HANDLE h = (HANDLE) _get_osfhandle (fd);                    \
52                  if (GetFileType (h) == FILE_TYPE_PIPE)                      \
53                    {                                                         \
54                      /* h is a pipe or socket.  */                           \
55                      DWORD state;                                            \
56                      if (GetNamedPipeHandleState (h, &state, NULL, NULL,     \
57                                                   NULL, NULL, 0)             \
58                          && (state & PIPE_NOWAIT) != 0)                      \
59                        /* h is a pipe in non-blocking mode.                  \
60                           Change errno from ENOSPC to EAGAIN.  */            \
61                        errno = EAGAIN;                                       \
62                    }                                                         \
63                }                                                             \
64            }                                                                 \
65          else
66#  else
67#   define CLEAR_ERRNO
68#   define HANDLE_ENOSPC
69#  endif
70
71#  if GNULIB_SIGPIPE
72#   define CLEAR_LastError \
73      SetLastError (0);
74#   define HANDLE_ERROR_NO_DATA \
75          if (GetLastError () == ERROR_NO_DATA && ferror (stream))            \
76            {                                                                 \
77              int fd = fileno (stream);                                       \
78              if (fd >= 0                                                     \
79                  && GetFileType ((HANDLE) _get_osfhandle (fd))               \
80                     == FILE_TYPE_PIPE)                                       \
81                {                                                             \
82                  /* Try to raise signal SIGPIPE.  */                         \
83                  raise (SIGPIPE);                                            \
84                  /* If it is currently blocked or ignored, change errno from \
85                     EINVAL to EPIPE.  */                                     \
86                  errno = EPIPE;                                              \
87                }                                                             \
88            }                                                                 \
89          else
90#  else
91#   define CLEAR_LastError
92#   define HANDLE_ERROR_NO_DATA
93#  endif
94
95#  define CALL_WITH_SIGPIPE_EMULATION(RETTYPE, EXPRESSION, FAILED) \
96  if (ferror (stream))                                                        \
97    return (EXPRESSION);                                                      \
98  else                                                                        \
99    {                                                                         \
100      RETTYPE ret;                                                            \
101      CLEAR_ERRNO                                                             \
102      CLEAR_LastError                                                         \
103      ret = (EXPRESSION);                                                     \
104      if (FAILED)                                                             \
105        {                                                                     \
106          HANDLE_ENOSPC                                                       \
107          HANDLE_ERROR_NO_DATA                                                \
108          ;                                                                   \
109        }                                                                     \
110      return ret;                                                             \
111    }
112
113#  if !REPLACE_PRINTF_POSIX /* avoid collision with printf.c */
114int
115printf (const char *format, ...)
116{
117  int retval;
118  va_list args;
119
120  va_start (args, format);
121  retval = vfprintf (stdout, format, args);
122  va_end (args);
123
124  return retval;
125}
126#  endif
127
128#  if !REPLACE_FPRINTF_POSIX /* avoid collision with fprintf.c */
129int
130fprintf (FILE *stream, const char *format, ...)
131{
132  int retval;
133  va_list args;
134
135  va_start (args, format);
136  retval = vfprintf (stream, format, args);
137  va_end (args);
138
139  return retval;
140}
141#  endif
142
143#  if !REPLACE_VPRINTF_POSIX /* avoid collision with vprintf.c */
144int
145vprintf (const char *format, va_list args)
146{
147  return vfprintf (stdout, format, args);
148}
149#  endif
150
151#  if !REPLACE_VFPRINTF_POSIX /* avoid collision with vfprintf.c */
152int
153vfprintf (FILE *stream, const char *format, va_list args)
154#undef vfprintf
155{
156  CALL_WITH_SIGPIPE_EMULATION (int, vfprintf (stream, format, args), ret == EOF)
157}
158#  endif
159
160int
161putchar (int c)
162{
163  return fputc (c, stdout);
164}
165
166int
167fputc (int c, FILE *stream)
168#undef fputc
169{
170  CALL_WITH_SIGPIPE_EMULATION (int, fputc (c, stream), ret == EOF)
171}
172
173int
174fputs (const char *string, FILE *stream)
175#undef fputs
176{
177  CALL_WITH_SIGPIPE_EMULATION (int, fputs (string, stream), ret == EOF)
178}
179
180int
181puts (const char *string)
182#undef puts
183{
184  FILE *stream = stdout;
185  CALL_WITH_SIGPIPE_EMULATION (int, puts (string), ret == EOF)
186}
187
188size_t
189fwrite (const void *ptr, size_t s, size_t n, FILE *stream)
190#undef fwrite
191{
192  CALL_WITH_SIGPIPE_EMULATION (size_t, fwrite (ptr, s, n, stream), ret < n)
193}
194
195# endif
196#endif
197