1 /* Output stream referring to an stdio FILE.
2 Copyright (C) 2006, 2019 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2006.
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 <https://www.gnu.org/licenses/>. */
17
18 #include <config.h>
19
20 /* Specification. */
21 #include "file-ostream.h"
22
23 #include <errno.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #if HAVE_TCDRAIN
27 # include <termios.h>
28 #endif
29
30 #include "xalloc.h"
31
32 struct file_ostream : struct ostream
33 {
34 fields:
35 FILE *fp;
36 };
37
38 #if HAVE_TCDRAIN
39
40 /* EINTR handling for tcdrain().
41 This function can return -1/EINTR even though we don't have any
42 signal handlers set up, namely when we get interrupted via SIGSTOP. */
43
44 static inline int
nonintr_tcdrain(int fd)45 nonintr_tcdrain (int fd)
46 {
47 int retval;
48
49 do
50 retval = tcdrain (fd);
51 while (retval < 0 && errno == EINTR);
52
53 return retval;
54 }
55
56 #endif
57
58 /* Implementation of ostream_t methods. */
59
60 static void
write_mem(file_ostream_t stream,const void * data,size_t len)61 file_ostream::write_mem (file_ostream_t stream, const void *data, size_t len)
62 {
63 if (len > 0)
64 fwrite (data, 1, len, stream->fp);
65 }
66
67 static void
flush(file_ostream_t stream,ostream_flush_scope_t scope)68 file_ostream::flush (file_ostream_t stream, ostream_flush_scope_t scope)
69 {
70 /* This ostream has no internal buffer, therefore nothing to do for
71 scope == FLUSH_THIS_STREAM. */
72 if (scope != FLUSH_THIS_STREAM)
73 {
74 fflush (stream->fp);
75 if (scope == FLUSH_ALL)
76 {
77 int fd = fileno (stream->fp);
78 if (fd >= 0)
79 {
80 /* For streams connected to a disk file: */
81 fsync (fd);
82 #if HAVE_TCDRAIN
83 /* For streams connected to a terminal: */
84 nonintr_tcdrain (fd);
85 #endif
86 }
87 }
88 }
89 }
90
91 static void
free(file_ostream_t stream)92 file_ostream::free (file_ostream_t stream)
93 {
94 free (stream);
95 }
96
97 /* Constructor. */
98
99 file_ostream_t
file_ostream_create(FILE * fp)100 file_ostream_create (FILE *fp)
101 {
102 file_ostream_t stream = XMALLOC (struct file_ostream_representation);
103
104 stream->base.vtable = &file_ostream_vtable;
105 stream->fp = fp;
106
107 return stream;
108 }
109