1999-01-22 Roland McGrath <roland@baalperazim.frob.com>
[kopensolaris-gnu/glibc.git] / stdio / fwrite.c
1 /* Copyright (C) 1991, 92, 93, 94, 96, 97, 98 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3
4    The GNU C Library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Library General Public License as
6    published by the Free Software Foundation; either version 2 of the
7    License, or (at your option) any later version.
8
9    The GNU C Library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Library General Public License for more details.
13
14    You should have received a copy of the GNU Library General Public
15    License along with the GNU C Library; see the file COPYING.LIB.  If not,
16    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17    Boston, MA 02111-1307, USA.  */
18
19 #include <errno.h>
20 #include <stdio.h>
21 #include <string.h>
22
23
24 /* Write NMEMB chunks of SIZE bytes each from PTR onto STREAM.  */
25 size_t
26 fwrite (ptr, size, nmemb, stream)
27      const void *ptr;
28      size_t size;
29      size_t nmemb;
30      register FILE *stream;
31 {
32   register const unsigned char *p = (const unsigned char *) ptr;
33   register size_t to_write = size * nmemb;
34   register size_t written = 0;
35   int newlinep;
36   size_t buffer_space;
37   int default_func;
38
39   if (!__validfp (stream) || !stream->__mode.__write)
40     {
41       __set_errno (EINVAL);
42       return 0;
43     }
44
45   if (ferror (stream))
46     return 0;
47   if (p == NULL || to_write == 0)
48     return 0;
49
50   if (!stream->__seen || stream->__put_limit == stream->__buffer)
51     {
52       /* This stream has never been seen before.
53          Calling __flshfp will give it a buffer
54          and I/O functions if it needs them.  */
55       if (__flshfp (stream, *p++) == EOF)
56         return 0;
57       if (--to_write == 0)
58         return 1;
59       else
60         ++written;
61     }
62
63   default_func
64     = stream->__room_funcs.__output == __default_room_functions.__output;
65
66   {
67     int save = errno;
68
69     if (__stdio_check_offset (stream) == EOF && errno != ESPIPE)
70       {
71         stream->__error = 1;
72         goto done;
73       }
74
75     __set_errno (save);
76   }
77
78   if (stream->__buffer == NULL && default_func &&
79       stream->__offset == stream->__target)
80   write_through:
81     /* This is an unbuffered stream using the standard output
82        buffer-flushing function, so we just do a straight write.  */
83     {
84       int count = (stream->__io_funcs.__write == NULL ? to_write :
85                    (*stream->__io_funcs.__write) (stream->__cookie,
86                                                   (const char *) p,
87                                                   to_write));
88       if (count > 0)
89         {
90           written += count;
91           if (stream->__offset != -1)
92             {
93               stream->__offset += count;
94               stream->__target = stream->__offset;
95             }
96           to_write -= count;
97           p += count;
98         }
99       else
100         stream->__error = 1;
101       goto done;
102     }
103
104   /* We ignore the end pointer here since we want to find out how much space
105      is really in the buffer, even for a line-buffered stream.  */
106   buffer_space = stream->__bufsize - (stream->__bufp - stream->__buffer);
107
108   newlinep = (stream->__linebuf &&
109               memchr ((const void *) p, '\n', to_write) != NULL);
110
111   if (newlinep && stream->__bufp == stream->__buffer &&
112       stream->__offset == stream->__target)
113     /* The buffer's empty, and we want to write our data
114        out soon anyway, so just write it straight out.  */
115     goto write_through;
116
117   if (stream->__bufsize == 0 && !default_func)
118     {
119       /* No buffer, and a special function.
120          We can't do much better than putc.  */
121       while (to_write-- > 0)
122         {
123           if (__flshfp (stream, *p++) == EOF)
124             break;
125           else
126             ++written;
127         }
128     }
129   else if (!default_func || buffer_space >= to_write)
130     {
131       /* There is enough room in the buffer for everything we want to write
132          or the user has specified his own output buffer-flushing/expanding
133          function.  */
134     fill_buffer:
135       while (to_write > 0)
136         {
137           register size_t n = to_write;
138
139           if (n > buffer_space)
140             n = buffer_space;
141
142           buffer_space -= n;
143
144           written += n;
145           to_write -= n;
146
147           if (n < 20)
148             while (n-- > 0)
149               *stream->__bufp++ = *p++;
150           else
151             {
152               memcpy ((void *) stream->__bufp, (void *) p, n);
153               stream->__bufp += n;
154               p += n;
155             }
156
157           if (to_write == 0)
158             /* Done writing.  */
159             break;
160           else if (buffer_space == 0)
161             {
162               /* We have filled the buffer, so flush it.  */
163               if (fflush (stream) == EOF)
164                 break;
165
166               /* Reset our record of the space available in the buffer,
167                  since we have just flushed it.  */
168             check_space:
169               buffer_space = (stream->__bufsize -
170                               (stream->__bufp - stream->__buffer));
171               if (buffer_space == 0)
172                 {
173                   /* With a custom output-room function, flushing might
174                      not create any buffer space.  Try writing a single
175                      character to create the space.  */
176                   if (__flshfp (stream, *p++) == EOF)
177                     goto done;
178                   ++written;
179                   --to_write;
180                   goto check_space;
181                 }
182             }
183         }
184
185       /* We have written all the data into the buffer.  If we are
186          line-buffered and just put a newline in the buffer, flush now to
187          make sure it gets out.  */
188       if (newlinep)
189         fflush (stream);
190     }
191   else
192     {
193       /* It won't all fit in the buffer.  */
194
195       if (stream->__bufp != stream->__buffer)
196         {
197           /* There are characters in the buffer.  Flush them.  */
198           if (__flshfp (stream, EOF) == EOF)
199             goto done;
200         }
201
202       /* The buffer has been flushed.
203          Now either fill it or write directly.  */
204
205       buffer_space = stream->__bufsize - (stream->__bufp - stream->__buffer);
206
207       if (stream->__offset == stream->__target &&
208           (buffer_space < to_write || newlinep))
209         /* What we have to write is bigger than the buffer,
210            or it contains a newline and we're line-buffered,
211            so write it out.  */
212         goto write_through;
213       else
214         /* It will fit in the buffer.  */
215         goto fill_buffer;
216     }
217
218  done:;
219   return (size_t) written / size;
220 }
221
222 weak_alias (fwrite, fwrite_unlocked)