(pututline_r): Since we assign RESULT from lseek now, check that it's >= 0, not...
[glibc.git] / stdio / fwrite.c
blob790c663aea45ed4cddb2bd8f7deaefab42359e37
1 /* Copyright (C) 1991, 1992, 1993, 1994, 1996 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)
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)
136 register size_t n = to_write;
138 if (n > buffer_space)
139 n = buffer_space;
141 buffer_space -= n;
143 written += n;
144 to_write -= n;
146 if (n < 20)
147 while (n-- > 0)
148 *stream->__bufp++ = *p++;
149 else
151 memcpy ((PTR) stream->__bufp, (PTR) p, n);
152 stream->__bufp += n;
153 p += n;
156 if (to_write == 0)
157 /* Done writing. */
158 break;
159 else if (buffer_space == 0)
161 /* We have filled the buffer, so flush it. */
162 if (fflush (stream) == EOF)
163 break;
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)
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;
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);
190 else
192 /* It won't all fit in the buffer. */
194 if (stream->__bufp != stream->__buffer)
196 /* There are characters in the buffer. Flush them. */
197 if (__flshfp (stream, EOF) == EOF)
198 goto done;
201 /* The buffer has been flushed.
202 Now either fill it or write directly. */
204 buffer_space = stream->__bufsize - (stream->__bufp - stream->__buffer);
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;
217 done:;
218 return (size_t) written / size;