• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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