Imported Upstream version 0.18.1.1
[platform/upstream/gettext.git] / gnulib-local / lib / fd-ostream.oo.c
1 /* Output stream referring to a file descriptor.
2    Copyright (C) 2006-2007 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 <http://www.gnu.org/licenses/>.  */
17
18 #include <config.h>
19
20 /* Specification.  */
21 #include "fd-ostream.h"
22
23 #include <assert.h>
24 #include <errno.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include "error.h"
29 #include "full-write.h"
30 #include "xalloc.h"
31 #include "gettext.h"
32
33 #define _(str) gettext (str)
34
35 struct fd_ostream : struct ostream
36 {
37 fields:
38   int fd;
39   char *filename;
40   char *buffer;                 /* A buffer, or NULL.  */
41   size_t avail;                 /* Number of bytes available in the buffer.  */
42 };
43
44 #define BUFSIZE 4096
45
46 /* Implementation of ostream_t methods.  */
47
48 static void
49 fd_ostream::write_mem (fd_ostream_t stream, const void *data, size_t len)
50 {
51   if (len > 0)
52     {
53       if (stream->buffer != NULL)
54         {
55           /* Buffered.  */
56           assert (stream->avail > 0);
57           #if 0 /* unoptimized */
58           do
59             {
60               size_t n = (len <= stream->avail ? len : stream->avail);
61               if (n > 0)
62                 {
63                   memcpy (stream->buffer + BUFSIZE - stream->avail, data, n);
64                   data = (char *) data + n;
65                   stream->avail -= n;
66                   len -= n;
67                 }
68               if (stream->avail == 0)
69                 {
70                   if (full_write (stream->fd, stream->buffer, BUFSIZE) < BUFSIZE)
71                     error (EXIT_FAILURE, errno, _("error writing to %s"),
72                            stream->filename);
73                   stream->avail = BUFSIZE;
74                 }
75             }
76           while (len > 0);
77           #else /* optimized */
78           if (len < stream->avail)
79             {
80               /* Move the data into the buffer.  */
81               memcpy (stream->buffer + BUFSIZE - stream->avail, data, len);
82               stream->avail -= len;
83             }
84           else
85             {
86               /* Split the data into:
87                    - a first chunk, which is added to the buffer and output,
88                    - a series of chunks of size BUFSIZE, which can be output
89                      directly, without going through the buffer, and
90                    - a last chunk, which is copied to the buffer.  */
91               size_t n = stream->avail;
92               memcpy (stream->buffer + BUFSIZE - stream->avail, data, n);
93               data = (char *) data + n;
94               len -= n;
95               if (full_write (stream->fd, stream->buffer, BUFSIZE) < BUFSIZE)
96                 error (EXIT_FAILURE, errno, _("error writing to %s"),
97                        stream->filename);
98
99               while (len >= BUFSIZE)
100                 {
101                   if (full_write (stream->fd, data, BUFSIZE) < BUFSIZE)
102                     error (EXIT_FAILURE, errno, _("error writing to %s"),
103                            stream->filename);
104                   data = (char *) data + BUFSIZE;
105                   len -= BUFSIZE;
106                 }
107
108               if (len > 0)
109                 memcpy (stream->buffer, data, len);
110               stream->avail = BUFSIZE - len;
111             }
112           #endif
113           assert (stream->avail > 0);
114         }
115       else
116         {
117           /* Unbuffered.  */
118           if (full_write (stream->fd, data, len) < len)
119             error (EXIT_FAILURE, errno, _("error writing to %s"),
120                    stream->filename);
121         }
122     }
123 }
124
125 static void
126 fd_ostream::flush (fd_ostream_t stream)
127 {
128   if (stream->buffer != NULL && stream->avail < BUFSIZE)
129     {
130       size_t filled = BUFSIZE - stream->avail;
131       if (full_write (stream->fd, stream->buffer, filled) < filled)
132         error (EXIT_FAILURE, errno, _("error writing to %s"), stream->filename);
133       stream->avail = BUFSIZE;
134     }
135 }
136
137 static void
138 fd_ostream::free (fd_ostream_t stream)
139 {
140   fd_ostream_flush (stream);
141   free (stream->filename);
142   free (stream);
143 }
144
145 /* Constructor.  */
146
147 fd_ostream_t
148 fd_ostream_create (int fd, const char *filename, bool buffered)
149 {
150   fd_ostream_t stream =
151     (struct fd_ostream_representation *)
152     xmalloc (sizeof (struct fd_ostream_representation)
153              + (buffered ? BUFSIZE : 0));
154
155   stream->base.vtable = &fd_ostream_vtable;
156   stream->fd = fd;
157   stream->filename = xstrdup (filename);
158   if (buffered)
159     {
160       stream->buffer =
161         (char *) (void *) stream + sizeof (struct fd_ostream_representation);
162       stream->avail = BUFSIZE;
163     }
164   else
165     stream->buffer = NULL;
166
167   return stream;
168 }