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