New file, incorporated from 4.4BSD-Lite for compatibility.
[glibc/history.git] / stdio / fwrite.c
blob4d012f1779b16baa3aa45fd3e9e42b2e67ca3f4c
1 /* Copyright (C) 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
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.
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.
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. */
19 #include <ansidecl.h>
20 #include <errno.h>
21 #include <stdio.h>
22 #include <string.h>
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)
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;
38 if (!__validfp (stream) || !stream->__mode.__write)
40 errno = EINVAL;
41 return 0;
44 if (ferror (stream))
45 return 0;
46 if (p == NULL || to_write == 0)
47 return 0;
49 if (!stream->__seen || stream->__put_limit == stream->__buffer)
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;
62 default_func
63 = stream->__room_funcs.__output == __default_room_functions.__output;
66 int save = errno;
68 if (__stdio_check_offset (stream) == EOF && errno != ESPIPE)
70 stream->__error = 1;
71 goto done;
74 errno = save;
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. */
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)
89 written += count;
90 if (stream->__offset != -1)
92 stream->__offset += count;
93 stream->__target = stream->__offset;
95 to_write -= count;
96 p += count;
98 else
99 stream->__error = 1;
100 goto done;
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);
107 newlinep = (stream->__linebuf &&
108 memchr ((CONST PTR) p, '\n', to_write) != NULL);
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;
116 if (stream->__bufsize == 0 && !default_func)
118 /* No buffer, and a special function.
119 We can't do much better than putc. */
120 while (to_write-- > 0)
122 if (__flshfp (stream, *p++) == EOF)
123 break;
124 else
125 ++written;
128 else if (!default_func || buffer_space >= to_write)
129 fill_buffer:
130 /* There is enough room in the buffer for everything we
131 want to write or the user has specified his own output
132 buffer-flushing/expanding function. */
133 while (to_write > 0)
135 register size_t n = to_write;
137 if (n > buffer_space)
138 n = buffer_space;
140 buffer_space -= n;
142 written += n;
143 to_write -= n;
145 if (n < 20)
146 while (n-- > 0)
147 *stream->__bufp++ = *p++;
148 else
150 memcpy ((PTR) stream->__bufp, (PTR) p, n);
151 stream->__bufp += n;
152 p += n;
155 if (buffer_space == 0 || (to_write == 0 && newlinep))
157 /* We've filled the buffer, so flush it. */
158 if (fflush (stream) == EOF)
159 break;
161 /* Reset our record of the space available in the buffer,
162 since we have just flushed it. */
163 check_space:
164 buffer_space = (stream->__bufsize -
165 (stream->__bufp - stream->__buffer));
166 if (buffer_space == 0)
168 /* With a custom output-room function, flushing might
169 not create any buffer space. Try writing a single
170 character to create the space. */
171 if (__flshfp (stream, *p++) == EOF)
172 goto done;
173 ++written;
174 --to_write;
175 goto check_space;
179 else
181 /* It won't all fit in the buffer. */
183 if (stream->__bufp != stream->__buffer)
185 /* There are characters in the buffer. Flush them. */
186 if (__flshfp (stream, EOF) == EOF)
187 goto done;
190 /* The buffer has been flushed.
191 Now either fill it or write directly. */
193 buffer_space = stream->__bufsize - (stream->__bufp - stream->__buffer);
195 if (stream->__offset == stream->__target &&
196 (buffer_space < to_write || newlinep))
197 /* What we have to write is bigger than the buffer,
198 or it contains a newline and we're line-buffered,
199 so write it out. */
200 goto write_through;
201 else
202 /* It will fit in the buffer. */
203 goto fill_buffer;
206 done:;
207 return (size_t) written / size;