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