1 /* DO NOT EDIT! GENERATED AUTOMATICALLY! */
2
3 #if !IS_CPLUSPLUS
4 #define fd_ostream_representation any_ostream_representation
5 #endif
6 #line 1 "fd-ostream.oo.c"
7 /* Output stream referring to a file descriptor.
8 Copyright (C) 2006-2007, 2019-2020 Free Software Foundation, Inc.
9 Written by Bruno Haible <bruno@clisp.org>, 2006.
10
11 This program is free software: you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 3 of the License, or
14 (at your option) any later version.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program. If not, see <https://www.gnu.org/licenses/>. */
23
24 #include <config.h>
25
26 /* Specification. */
27 #include "fd-ostream.h"
28
29 #include <assert.h>
30 #include <errno.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <unistd.h>
34 #if HAVE_TCDRAIN
35 # include <termios.h>
36 #endif
37
38 #include "error.h"
39 #include "full-write.h"
40 #include "xalloc.h"
41 #include "gettext.h"
42
43 #define _(str) gettext (str)
44
45 #line 46 "fd-ostream.c"
46 #include "fd_ostream.priv.h"
47
48 const typeinfo_t fd_ostream_typeinfo = { "fd_ostream" };
49
50 static const typeinfo_t * const fd_ostream_superclasses[] =
51 { fd_ostream_SUPERCLASSES };
52
53 #define super ostream_vtable
54
55 #line 47 "fd-ostream.oo.c"
56
57 #define BUFSIZE 4096
58
59 #if HAVE_TCDRAIN
60
61 /* EINTR handling for tcdrain().
62 This function can return -1/EINTR even though we don't have any
63 signal handlers set up, namely when we get interrupted via SIGSTOP. */
64
65 static inline int
66 nonintr_tcdrain (int fd)
67 {
68 int retval;
69
70 do
71 retval = tcdrain (fd);
72 while (retval < 0 && errno == EINTR);
73
74 return retval;
75 }
76
77 #endif
78
79 /* Implementation of ostream_t methods. */
80
81 static void
82 fd_ostream__write_mem (fd_ostream_t stream, const void *data, size_t len)
83 {
84 if (len > 0)
85 {
86 if (stream->buffer != NULL)
87 {
88 /* Buffered. */
89 assert (stream->avail > 0);
90 #if 0 /* unoptimized */
91 do
92 {
93 size_t n = (len <= stream->avail ? len : stream->avail);
94 if (n > 0)
95 {
96 memcpy (stream->buffer + BUFSIZE - stream->avail, data, n);
97 data = (const char *) data + n;
98 stream->avail -= n;
99 len -= n;
100 }
101 if (stream->avail == 0)
102 {
103 if (full_write (stream->fd, stream->buffer, BUFSIZE) < BUFSIZE)
104 error (EXIT_FAILURE, errno, _("error writing to %s"),
105 stream->filename);
106 stream->avail = BUFSIZE;
107 }
108 }
109 while (len > 0);
110 #else /* optimized */
111 if (len < stream->avail)
112 {
113 /* Move the data into the buffer. */
114 memcpy (stream->buffer + BUFSIZE - stream->avail, data, len);
115 stream->avail -= len;
116 }
117 else
118 {
119 /* Split the data into:
120 - a first chunk, which is added to the buffer and output,
121 - a series of chunks of size BUFSIZE, which can be output
122 directly, without going through the buffer, and
123 - a last chunk, which is copied to the buffer. */
124 size_t n = stream->avail;
125 memcpy (stream->buffer + BUFSIZE - stream->avail, data, n);
126 data = (const char *) data + n;
127 len -= n;
128 if (full_write (stream->fd, stream->buffer, BUFSIZE) < BUFSIZE)
129 error (EXIT_FAILURE, errno, _("error writing to %s"),
130 stream->filename);
131
132 while (len >= BUFSIZE)
133 {
134 if (full_write (stream->fd, data, BUFSIZE) < BUFSIZE)
135 error (EXIT_FAILURE, errno, _("error writing to %s"),
136 stream->filename);
137 data = (const char *) data + BUFSIZE;
138 len -= BUFSIZE;
139 }
140
141 if (len > 0)
142 memcpy (stream->buffer, data, len);
143 stream->avail = BUFSIZE - len;
144 }
145 #endif
146 assert (stream->avail > 0);
147 }
148 else
149 {
150 /* Unbuffered. */
151 if (full_write (stream->fd, data, len) < len)
152 error (EXIT_FAILURE, errno, _("error writing to %s"),
153 stream->filename);
154 }
155 }
156 }
157
158 static void
159 fd_ostream__flush (fd_ostream_t stream, ostream_flush_scope_t scope)
160 {
161 if (stream->buffer != NULL && stream->avail < BUFSIZE)
162 {
163 size_t filled = BUFSIZE - stream->avail;
164 if (full_write (stream->fd, stream->buffer, filled) < filled)
165 error (EXIT_FAILURE, errno, _("error writing to %s"), stream->filename);
166 stream->avail = BUFSIZE;
167 }
168 if (scope == FLUSH_ALL)
169 {
170 /* For streams connected to a disk file: */
171 fsync (stream->fd);
172 #if HAVE_TCDRAIN
173 /* For streams connected to a terminal: */
174 nonintr_tcdrain (stream->fd);
175 #endif
176 }
177 }
178
179 static void
180 fd_ostream__free (fd_ostream_t stream)
181 {
182 fd_ostream_flush (stream, FLUSH_THIS_STREAM);
183 free (stream->filename);
184 free (stream);
185 }
186
187 /* Constructor. */
188
189 fd_ostream_t
190 fd_ostream_create (int fd, const char *filename, bool buffered)
191 {
192 fd_ostream_t stream =
193 (struct fd_ostream_representation *)
194 xmalloc (sizeof (struct fd_ostream_representation)
195 + (buffered ? BUFSIZE : 0));
196
197 stream->base.vtable = &fd_ostream_vtable;
198 stream->fd = fd;
199 stream->filename = xstrdup (filename);
200 if (buffered)
201 {
202 stream->buffer =
203 (char *) (void *) stream + sizeof (struct fd_ostream_representation);
204 stream->avail = BUFSIZE;
205 }
206 else
207 stream->buffer = NULL;
208
209 return stream;
210 }
211
212 /* Accessors. */
213
214 static int
215 fd_ostream__get_descriptor (fd_ostream_t stream)
216 {
217 return stream->fd;
218 }
219
220 static const char *
221 fd_ostream__get_filename (fd_ostream_t stream)
222 {
223 return stream->filename;
224 }
225
226 static bool
227 fd_ostream__is_buffered (fd_ostream_t stream)
228 {
229 return stream->buffer != NULL;
230 }
231
232 /* Instanceof test. */
233
234 bool
235 is_instance_of_fd_ostream (ostream_t stream)
236 {
237 return IS_INSTANCE (stream, ostream, fd_ostream);
238 }
239
240 #line 241 "fd-ostream.c"
241
242 const struct fd_ostream_implementation fd_ostream_vtable =
243 {
244 fd_ostream_superclasses,
245 sizeof (fd_ostream_superclasses) / sizeof (fd_ostream_superclasses[0]),
246 sizeof (struct fd_ostream_representation),
247 fd_ostream__write_mem,
248 fd_ostream__flush,
249 fd_ostream__free,
250 fd_ostream__get_descriptor,
251 fd_ostream__get_filename,
252 fd_ostream__is_buffered,
253 };
254
255 #if !HAVE_INLINE
256
257 /* Define the functions that invoke the methods. */
258
259 void
260 fd_ostream_write_mem (fd_ostream_t first_arg, const void *data, size_t len)
261 {
262 const struct fd_ostream_implementation *vtable =
263 ((struct fd_ostream_representation_header *) (struct fd_ostream_representation *) first_arg)->vtable;
264 vtable->write_mem (first_arg,data,len);
265 }
266
267 void
268 fd_ostream_flush (fd_ostream_t first_arg, ostream_flush_scope_t scope)
269 {
270 const struct fd_ostream_implementation *vtable =
271 ((struct fd_ostream_representation_header *) (struct fd_ostream_representation *) first_arg)->vtable;
272 vtable->flush (first_arg,scope);
273 }
274
275 void
276 fd_ostream_free (fd_ostream_t first_arg)
277 {
278 const struct fd_ostream_implementation *vtable =
279 ((struct fd_ostream_representation_header *) (struct fd_ostream_representation *) first_arg)->vtable;
280 vtable->free (first_arg);
281 }
282
283 int
284 fd_ostream_get_descriptor (fd_ostream_t first_arg)
285 {
286 const struct fd_ostream_implementation *vtable =
287 ((struct fd_ostream_representation_header *) (struct fd_ostream_representation *) first_arg)->vtable;
288 return vtable->get_descriptor (first_arg);
289 }
290
291 const char *
292 fd_ostream_get_filename (fd_ostream_t first_arg)
293 {
294 const struct fd_ostream_implementation *vtable =
295 ((struct fd_ostream_representation_header *) (struct fd_ostream_representation *) first_arg)->vtable;
296 return vtable->get_filename (first_arg);
297 }
298
299 bool
300 fd_ostream_is_buffered (fd_ostream_t first_arg)
301 {
302 const struct fd_ostream_implementation *vtable =
303 ((struct fd_ostream_representation_header *) (struct fd_ostream_representation *) first_arg)->vtable;
304 return vtable->is_buffered (first_arg);
305 }
306
307 #endif