entered into RCS
[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   {
66     int save = errno;
67
68     if (__stdio_check_offset (stream) == EOF && errno != ESPIPE)
69       {
70         stream->__error = 1;
71         goto done;
72       }
73
74     errno = save;
75   }
76
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.  */
82     {
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)
88         {
89           written += count;
90           if (stream->__offset != -1)
91             {
92               stream->__offset += count;
93               stream->__target = stream->__offset;
94             }
95           to_write -= count;
96           p += count;
97         }
98       else
99         stream->__error = 1;
100       goto done;
101     }
102
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);
106
107   newlinep = (stream->__linebuf &&
108               memchr ((CONST PTR) p, '\n', to_write) != NULL);
109
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;
115
116   if (stream->__bufsize == 0 && !default_func)
117     {
118       /* No buffer, and a special function.
119          We can't do much better than putc.  */
120       while (to_write-- > 0)
121         {
122           if (__flshfp (stream, *p++) == EOF)
123             break;
124           else
125             ++written;
126         }
127     }
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)
134       {
135         register size_t n = to_write;
136
137         if (n > buffer_space)
138           n = buffer_space;
139
140         buffer_space -= n;
141
142         written += n;
143         to_write -= n;
144
145         if (n < 20)
146           while (n-- > 0)
147             *stream->__bufp++ = *p++;
148         else
149           {
150             memcpy ((PTR) stream->__bufp, (PTR) p, n);
151             stream->__bufp += n;
152             p += n;
153           }
154
155         if (buffer_space == 0 || (to_write == 0 && newlinep))
156           {
157             /* We've filled the buffer, so flush it.  */
158             if (fflush (stream) == EOF)
159               break;
160           }
161       }
162   else
163     {
164       /* It won't all fit in the buffer.  */
165
166       if (stream->__bufp != stream->__buffer)
167         {
168           /* There are characters in the buffer.  Flush them.  */
169           if (__flshfp (stream, EOF) == EOF)
170             goto done;
171         }
172
173       /* The buffer has been flushed.
174          Now either fill it or write directly.  */
175
176       buffer_space = stream->__bufsize - (stream->__bufp - stream->__buffer);
177
178       if (stream->__offset == stream->__target &&
179           (buffer_space < to_write || newlinep))
180         /* What we have to write is bigger than the buffer,
181            or it contains a newline and we're line-buffered,
182            so write it out.  */
183         goto write_through;
184       else
185         /* It will fit in the buffer.  */
186         goto fill_buffer;
187     }
188
189  done:;
190   return (size_t) written / size;
191 }