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