Initial revision
[kopensolaris-gnu/glibc.git] / stdio / fwrite.c
1 /* Copyright (C) 1991 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 char *p = (CONST 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   char 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   if (stream->__buffer == NULL && default_func &&
66       stream->__offset == stream->__target)
67   write_through:
68     /* This is an unbuffered stream using the standard output
69        buffer-flushing function, so we just do a straight write.  */
70     {
71       int count = (stream->__io_funcs.__write == NULL ? to_write :
72                    (*stream->__io_funcs.__write)(stream->__cookie, p,
73                                                  to_write));
74       if (count > 0)
75         {
76           written += count;
77           stream->__offset += count;
78           stream->__target = stream->__offset;
79           to_write -= count;
80           p += count;
81         }
82       else
83         stream->__error = 1;
84       goto done;
85     }
86
87   /* We ignore the end pointer here since we want to find out how much space
88      is really in the buffer, even for a line-buffered stream.  */
89   buffer_space = stream->__bufsize - (stream->__bufp - stream->__buffer);
90
91   newlinep = (stream->__linebuf &&
92               memchr((CONST PTR) p, '\n', to_write) != NULL);
93
94   if (newlinep && stream->__bufp == stream->__buffer &&
95       stream->__offset == stream->__target)
96     /* The buffer's empty, and we want to write our data
97        out soon anyway, so just write it straight out.  */
98     goto write_through;
99
100   if (stream->__bufsize == 0 && !default_func)
101     {
102       /* No buffer, and a special function.
103          We can't do much better than putc.  */
104       while (to_write-- > 0)
105         {
106           if (__flshfp(stream, *p++) == EOF)
107             break;
108           else
109             ++written;
110         }
111     }
112   else if (!default_func || buffer_space >= to_write)
113   fill_buffer:
114     /* There is enough room in the buffer for everything we
115        want to write or the user has specified his own output
116        buffer-flushing/expanding function.  */
117     while (to_write > 0)
118       {
119         register size_t n = to_write;
120
121         if (n > buffer_space)
122           n = buffer_space;
123
124         buffer_space -= n;
125
126         written += n;
127         to_write -= n;
128
129         if (n < 20)
130           while (n-- > 0)
131             *stream->__bufp++ = *p++;
132         else
133           {
134             memcpy((PTR) stream->__bufp, (PTR) p, n);
135             stream->__bufp += n;
136             p += n;
137           }
138
139         if (buffer_space == 0 || (to_write == 0 && newlinep))
140           {
141             /* We've filled the buffer, so flush it.  */
142             if (fflush(stream) == EOF)
143               break;
144           }
145       }
146   else
147     {
148       /* It won't all fit in the buffer.  */
149
150       if (stream->__bufp != stream->__buffer)
151         {
152           /* There are characters in the buffer.  Flush them.  */
153           if (__flshfp(stream, EOF) == EOF)
154             goto done;
155         }
156
157       /* The buffer has been flushed.
158          Now either fill it or write directly.  */
159
160       buffer_space = stream->__put_limit - stream->__bufp;
161
162       if (stream->__offset == stream->__target &&
163           (buffer_space < to_write || newlinep))
164         /* What we have to write is bigger than the buffer,
165            or it contains a newline and we're line-buffered,
166            so write it out.  */
167         goto write_through;
168       else
169         /* It will fit in the buffer.  */
170         goto fill_buffer;
171     }
172
173  done:;
174   return (size_t) written / size;
175 }