Update and reformat copyright. Protect use of weak_alias. Use _IO_*
[kopensolaris-gnu/glibc.git] / libio / fileops.c
1 /* Copyright (C) 1993, 1995, 1997 Free Software Foundation, Inc.
2    This file is part of the GNU IO Library.
3    Written by Per Bothner <bothner@cygnus.com>.
4
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU General Public License as
7    published by the Free Software Foundation; either version 2, or (at
8    your option) any later version.
9
10    This library is distributed in the hope that it will be useful, but
11    WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this library; see the file COPYING.  If not, write to
17    the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
18    MA 02111-1307, USA.
19
20    As a special exception, if you link this library with files
21    compiled with a GNU compiler to produce an executable, this does
22    not cause the resulting executable to be covered by the GNU General
23    Public License.  This exception does not however invalidate any
24    other reasons why the executable file might be covered by the GNU
25    General Public License.  */
26
27
28 #ifndef _POSIX_SOURCE
29 # define _POSIX_SOURCE
30 #endif
31 #include "libioP.h"
32 #include <fcntl.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <string.h>
36 #include <errno.h>
37 #ifndef errno
38 extern int errno;
39 #endif
40
41
42 #ifdef _LIBC
43 # define open(Name, Flags, Prot) __open ((Name), (Flags), (Prot))
44 #endif
45
46 /* An fstream can be in at most one of put mode, get mode, or putback mode.
47    Putback mode is a variant of get mode.
48
49    In a filebuf, there is only one current position, instead of two
50    separate get and put pointers.  In get mode, the current position
51    is that of gptr(); in put mode that of pptr().
52
53    The position in the buffer that corresponds to the position
54    in external file system is normally _IO_read_end, except in putback
55    mode, when it is _IO_save_end.
56    If the field _fb._offset is >= 0, it gives the offset in
57    the file as a whole corresponding to eGptr(). (?)
58
59    PUT MODE:
60    If a filebuf is in put mode, then all of _IO_read_ptr, _IO_read_end,
61    and _IO_read_base are equal to each other.  These are usually equal
62    to _IO_buf_base, though not necessarily if we have switched from
63    get mode to put mode.  (The reason is to maintain the invariant
64    that _IO_read_end corresponds to the external file position.)
65    _IO_write_base is non-NULL and usually equal to _IO_base_base.
66    We also have _IO_write_end == _IO_buf_end, but only in fully buffered mode.
67    The un-flushed character are those between _IO_write_base and _IO_write_ptr.
68
69    GET MODE:
70    If a filebuf is in get or putback mode, eback() != egptr().
71    In get mode, the unread characters are between gptr() and egptr().
72    The OS file position corresponds to that of egptr().
73
74    PUTBACK MODE:
75    Putback mode is used to remember "excess" characters that have
76    been sputbackc'd in a separate putback buffer.
77    In putback mode, the get buffer points to the special putback buffer.
78    The unread characters are the characters between gptr() and egptr()
79    in the putback buffer, as well as the area between save_gptr()
80    and save_egptr(), which point into the original reserve buffer.
81    (The pointers save_gptr() and save_egptr() are the values
82    of gptr() and egptr() at the time putback mode was entered.)
83    The OS position corresponds to that of save_egptr().
84
85    LINE BUFFERED OUTPUT:
86    During line buffered output, _IO_write_base==base() && epptr()==base().
87    However, ptr() may be anywhere between base() and ebuf().
88    This forces a call to filebuf::overflow(int C) on every put.
89    If there is more space in the buffer, and C is not a '\n',
90    then C is inserted, and pptr() incremented.
91
92    UNBUFFERED STREAMS:
93    If a filebuf is unbuffered(), the _shortbuf[1] is used as the buffer.
94 */
95
96 #define CLOSED_FILEBUF_FLAGS \
97   (_IO_IS_FILEBUF+_IO_NO_READS+_IO_NO_WRITES+_IO_TIED_PUT_GET)
98
99
100 void
101 _IO_file_init (fp)
102      _IO_FILE *fp;
103 {
104   /* POSIX.1 allows another file handle to be used to change the position
105      of our file descriptor.  Hence we actually don't know the actual
106      position before we do the first fseek (and until a following fflush). */
107   fp->_offset = _IO_pos_BAD;
108   fp->_IO_file_flags |= CLOSED_FILEBUF_FLAGS;
109
110   _IO_link_in(fp);
111   fp->_fileno = -1;
112 }
113
114 int
115 _IO_file_close_it (fp)
116      _IO_FILE *fp;
117 {
118   int write_status, close_status;
119   if (!_IO_file_is_open (fp))
120     return EOF;
121
122   write_status = _IO_do_flush (fp);
123
124   _IO_unsave_markers(fp);
125
126   close_status = _IO_SYSCLOSE (fp);
127
128   /* Free buffer. */
129   _IO_setb (fp, NULL, NULL, 0);
130   _IO_setg (fp, NULL, NULL, NULL);
131   _IO_setp (fp, NULL, NULL);
132
133   _IO_un_link (fp);
134   fp->_flags = _IO_MAGIC|CLOSED_FILEBUF_FLAGS;
135   fp->_fileno = EOF;
136   fp->_offset = _IO_pos_BAD;
137
138   return close_status ? close_status : write_status;
139 }
140
141 void
142 _IO_file_finish (fp, dummy)
143      _IO_FILE *fp;
144      int dummy;
145 {
146   if (_IO_file_is_open (fp))
147     {
148       _IO_do_flush (fp);
149       if (!(fp->_flags & _IO_DELETE_DONT_CLOSE))
150         _IO_SYSCLOSE (fp);
151     }
152   _IO_default_finish (fp, 0);
153 }
154
155 _IO_FILE *
156 _IO_file_fopen (fp, filename, mode)
157      _IO_FILE *fp;
158      const char *filename;
159      const char *mode;
160 {
161   int oflags = 0, omode;
162   int read_write, fdesc;
163   int oprot = 0666;
164   if (_IO_file_is_open (fp))
165     return 0;
166   switch (*mode++)
167     {
168     case 'r':
169       omode = O_RDONLY;
170       read_write = _IO_NO_WRITES;
171       break;
172     case 'w':
173       omode = O_WRONLY;
174       oflags = O_CREAT|O_TRUNC;
175       read_write = _IO_NO_READS;
176       break;
177     case 'a':
178       omode = O_WRONLY;
179       oflags = O_CREAT|O_APPEND;
180       read_write = _IO_NO_READS|_IO_IS_APPENDING;
181       break;
182     default:
183       __set_errno (EINVAL);
184       return NULL;
185     }
186   if (mode[0] == '+' || (mode[0] == 'b' && mode[1] == '+'))
187     {
188       omode = O_RDWR;
189       read_write &= _IO_IS_APPENDING;
190     }
191   fdesc = open (filename, omode|oflags, oprot);
192   if (fdesc < 0)
193     return NULL;
194   fp->_fileno = fdesc;
195   _IO_mask_flags (fp, read_write,_IO_NO_READS+_IO_NO_WRITES+_IO_IS_APPENDING);
196   if (read_write & _IO_IS_APPENDING)
197     if (_IO_SEEKOFF (fp, (_IO_off_t)0, _IO_seek_end, _IOS_INPUT|_IOS_OUTPUT)
198         == _IO_pos_BAD && errno != ESPIPE)
199       return NULL;
200   _IO_link_in (fp);
201   return fp;
202 }
203
204 _IO_FILE *
205 _IO_file_attach (fp, fd)
206      _IO_FILE *fp;
207      int fd;
208 {
209   if (_IO_file_is_open (fp))
210     return NULL;
211   fp->_fileno = fd;
212   fp->_flags &= ~(_IO_NO_READS+_IO_NO_WRITES);
213   fp->_flags |= _IO_DELETE_DONT_CLOSE;
214   /* Get the current position of the file. */
215   /* We have to do that since that may be junk. */
216   fp->_offset = _IO_pos_BAD;
217   if (_IO_SEEKOFF (fp, (_IO_off_t)0, _IO_seek_cur, _IOS_INPUT|_IOS_OUTPUT)
218       == _IO_pos_BAD && errno != ESPIPE)
219     return NULL;
220   return fp;
221 }
222
223 _IO_FILE *
224 _IO_file_setbuf (fp, p, len)
225      _IO_FILE *fp;
226      char *p;
227      _IO_ssize_t len;
228 {
229     if (_IO_default_setbuf (fp, p, len) == NULL)
230       return NULL;
231
232     fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_write_end
233       = fp->_IO_buf_base;
234     _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
235
236     return fp;
237 }
238
239 /* Write TO_DO bytes from DATA to FP.
240    Then mark FP as having empty buffers. */
241
242 int
243 _IO_do_write (fp, data, to_do)
244      _IO_FILE *fp;
245      const char *data;
246      _IO_size_t to_do;
247 {
248   _IO_size_t count;
249   if (to_do == 0)
250     return 0;
251   if (fp->_flags & _IO_IS_APPENDING)
252     /* On a system without a proper O_APPEND implementation,
253        you would need to sys_seek(0, SEEK_END) here, but is
254        is not needed nor desirable for Unix- or Posix-like systems.
255        Instead, just indicate that offset (before and after) is
256        unpredictable. */
257     fp->_offset = _IO_pos_BAD;
258   else if (fp->_IO_read_end != fp->_IO_write_base)
259     {
260       _IO_pos_t new_pos
261         = _IO_SYSSEEK (fp, fp->_IO_write_base - fp->_IO_read_end, 1);
262       if (new_pos == _IO_pos_BAD)
263         return EOF;
264       fp->_offset = new_pos;
265     }
266   count = _IO_SYSWRITE (fp, data, to_do);
267   if (fp->_cur_column)
268     fp->_cur_column = _IO_adjust_column (fp->_cur_column - 1, data, to_do) + 1;
269   _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
270   fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_buf_base;
271   fp->_IO_write_end = ((fp->_flags & (_IO_LINE_BUF+_IO_UNBUFFERED))
272                        ? fp->_IO_buf_base : fp->_IO_buf_end);
273   return count != to_do ? EOF : 0;
274 }
275
276 int
277 _IO_file_underflow (fp)
278      _IO_FILE *fp;
279 {
280   _IO_ssize_t count;
281 #if 0
282   /* SysV does not make this test; take it out for compatibility */
283   if (fp->_flags & _IO_EOF_SEEN)
284     return (EOF);
285 #endif
286
287   if (fp->_flags & _IO_NO_READS)
288     {
289       __set_errno (EBADF);
290       return EOF;
291     }
292   if (fp->_IO_read_ptr < fp->_IO_read_end)
293     return *(unsigned char *) fp->_IO_read_ptr;
294
295   if (fp->_IO_buf_base == NULL)
296     _IO_doallocbuf (fp);
297
298   /* Flush all line buffered files before reading. */
299   /* FIXME This can/should be moved to genops ?? */
300   if (fp->_flags & (_IO_LINE_BUF|_IO_UNBUFFERED))
301     _IO_flush_all_linebuffered ();
302
303   _IO_switch_to_get_mode (fp);
304
305   /* This is very tricky. We have to adjust those
306      pointers before we call _IO_SYSREAD () since
307      we may longjump () out while waiting for
308      input. Those pointers may be screwed up. H.J. */
309   fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_buf_base;
310   fp->_IO_read_end = fp->_IO_buf_base;
311   fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_write_end
312     = fp->_IO_buf_base;
313
314   count = _IO_SYSREAD (fp, fp->_IO_buf_base,
315                        fp->_IO_buf_end - fp->_IO_buf_base);
316   if (count <= 0)
317     {
318       if (count == 0)
319         fp->_flags |= _IO_EOF_SEEN;
320       else
321         fp->_flags |= _IO_ERR_SEEN, count = 0;
322   }
323   fp->_IO_read_end += count;
324   if (count == 0)
325     return EOF;
326   if (fp->_offset != _IO_pos_BAD)
327     _IO_pos_adjust (fp->_offset, count);
328   return *(unsigned char *) fp->_IO_read_ptr;
329 }
330
331 int
332 _IO_file_overflow (f, ch)
333       _IO_FILE *f;
334       int ch;
335 {
336   if (f->_flags & _IO_NO_WRITES) /* SET ERROR */
337     {
338       f->_flags |= _IO_ERR_SEEN;
339       __set_errno (EBADF);
340       return EOF;
341     }
342   /* If currently reading or no buffer allocated. */
343   if ((f->_flags & _IO_CURRENTLY_PUTTING) == 0)
344     {
345       /* Allocate a buffer if needed. */
346       if (f->_IO_write_base == 0)
347         {
348           _IO_doallocbuf (f);
349           _IO_setg (f, f->_IO_buf_base, f->_IO_buf_base, f->_IO_buf_base);
350         }
351       /* Otherwise must be currently reading.
352          If _IO_read_ptr (and hence also _IO_read_end) is at the buffer end,
353          logically slide the buffer forwards one block (by setting the
354          read pointers to all point at the beginning of the block).  This
355          makes room for subsequent output.
356          Otherwise, set the read pointers to _IO_read_end (leaving that
357          alone, so it can continue to correspond to the external position). */
358       if (f->_IO_read_ptr == f->_IO_buf_end)
359         f->_IO_read_end = f->_IO_read_ptr = f->_IO_buf_base;
360       f->_IO_write_ptr = f->_IO_read_ptr;
361       f->_IO_write_base = f->_IO_write_ptr;
362       f->_IO_write_end = f->_IO_buf_end;
363       f->_IO_read_base = f->_IO_read_ptr = f->_IO_read_end;
364
365       if (f->_flags & (_IO_LINE_BUF+_IO_UNBUFFERED))
366         f->_IO_write_end = f->_IO_write_ptr;
367       f->_flags |= _IO_CURRENTLY_PUTTING;
368     }
369   if (ch == EOF)
370     return _IO_do_flush (f);
371   if (f->_IO_write_ptr == f->_IO_buf_end ) /* Buffer is really full */
372     if (_IO_do_flush (f) == EOF)
373       return EOF;
374   *f->_IO_write_ptr++ = ch;
375   if ((f->_flags & _IO_UNBUFFERED)
376       || ((f->_flags & _IO_LINE_BUF) && ch == '\n'))
377     if (_IO_do_flush (f) == EOF)
378       return EOF;
379   return (unsigned char) ch;
380 }
381
382 int
383 _IO_file_sync (fp)
384      _IO_FILE *fp;
385 {
386   _IO_size_t delta;
387   /*    char* ptr = cur_ptr(); */
388   if (fp->_IO_write_ptr > fp->_IO_write_base)
389     if (_IO_do_flush(fp)) return EOF;
390   delta = fp->_IO_read_ptr - fp->_IO_read_end;
391   if (delta != 0)
392     {
393 #ifdef TODO
394       if (_IO_in_backup (fp))
395         delta -= eGptr () - Gbase ();
396 #endif
397       _IO_off_t new_pos = _IO_SYSSEEK (fp, delta, 1);
398       if (new_pos != (_IO_off_t) EOF)
399         fp->_IO_read_end = fp->_IO_read_ptr;
400 #ifdef ESPIPE
401       else if (errno == ESPIPE)
402         ; /* Ignore error from unseekable devices. */
403 #endif
404       else
405         return EOF;
406     }
407   fp->_offset = _IO_pos_BAD;
408   /* FIXME: Cleanup - can this be shared? */
409   /*    setg(base(), ptr, ptr); */
410   return 0;
411 }
412
413 _IO_pos_t
414 _IO_file_seekoff (fp, offset, dir, mode)
415      _IO_FILE *fp;
416      _IO_off_t offset;
417      int dir;
418      int mode;
419 {
420   _IO_pos_t result;
421   _IO_off_t delta, new_offset;
422   long count;
423   /* POSIX.1 8.2.3.7 says that after a call the fflush() the file
424      offset of the underlying file must be exact.  */
425   int must_be_exact = (fp->_IO_read_base == fp->_IO_read_end
426                        && fp->_IO_write_base == fp->_IO_write_ptr);
427
428   if (mode == 0)
429     dir = _IO_seek_cur, offset = 0; /* Don't move any pointers. */
430
431   /* Flush unwritten characters.
432      (This may do an unneeded write if we seek within the buffer.
433      But to be able to switch to reading, we would need to set
434      egptr to ptr.  That can't be done in the current design,
435      which assumes file_ptr() is eGptr.  Anyway, since we probably
436      end up flushing when we close(), it doesn't make much difference.)
437      FIXME: simulate mem-papped files. */
438
439   if (fp->_IO_write_ptr > fp->_IO_write_base || _IO_in_put_mode (fp))
440     if (_IO_switch_to_get_mode (fp))
441       return EOF;
442
443   if (fp->_IO_buf_base == NULL)
444     {
445       _IO_doallocbuf (fp);
446       _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
447       _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
448     }
449
450   switch (dir)
451     {
452     case _IO_seek_cur:
453       /* Adjust for read-ahead (bytes is buffer). */
454       offset -= fp->_IO_read_end - fp->_IO_read_ptr;
455       if (fp->_offset == _IO_pos_BAD)
456         goto dumb;
457       /* Make offset absolute, assuming current pointer is file_ptr(). */
458       offset += _IO_pos_as_off (fp->_offset);
459
460       dir = _IO_seek_set;
461       break;
462     case _IO_seek_set:
463       break;
464     case _IO_seek_end:
465       {
466         struct stat st;
467         if (_IO_SYSSTAT (fp, &st) == 0 && S_ISREG (st.st_mode))
468           {
469             offset += st.st_size;
470             dir = _IO_seek_set;
471           }
472         else
473           goto dumb;
474       }
475     }
476   /* At this point, dir==_IO_seek_set. */
477
478   /* If destination is within current buffer, optimize: */
479   if (fp->_offset != _IO_pos_BAD && fp->_IO_read_base != NULL
480       && !_IO_in_backup (fp))
481     {
482       /* Offset relative to start of main get area. */
483       _IO_pos_t rel_offset = (offset - fp->_offset
484                               + (fp->_IO_read_end - fp->_IO_read_base));
485       if (rel_offset >= 0)
486         {
487 #if 0
488           if (_IO_in_backup (fp))
489             _IO_switch_to_main_get_area (fp);
490 #endif
491           if (rel_offset <= fp->_IO_read_end - fp->_IO_read_base)
492             {
493               _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base + rel_offset,
494                         fp->_IO_read_end);
495               _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
496               return offset;
497             }
498 #ifdef TODO
499             /* If we have streammarkers, seek forward by reading ahead. */
500             if (_IO_have_markers (fp))
501               {
502                 int to_skip = rel_offset
503                   - (fp->_IO_read_ptr - fp->_IO_read_base);
504                 if (ignore (to_skip) != to_skip)
505                   goto dumb;
506                 return offset;
507               }
508 #endif
509         }
510 #ifdef TODO
511       if (rel_offset < 0 && rel_offset >= Bbase () - Bptr ())
512         {
513           if (!_IO_in_backup (fp))
514             _IO_switch_to_backup_area (fp);
515           gbump (fp->_IO_read_end + rel_offset - fp->_IO_read_ptr);
516           return offset;
517         }
518 #endif
519     }
520
521 #ifdef TODO
522   _IO_unsave_markers (fp);
523 #endif
524
525   if (fp->_flags & _IO_NO_READS)
526     goto dumb;
527
528   /* Try to seek to a block boundary, to improve kernel page management. */
529   new_offset = offset & ~(fp->_IO_buf_end - fp->_IO_buf_base - 1);
530   delta = offset - new_offset;
531   if (delta > fp->_IO_buf_end - fp->_IO_buf_base)
532     {
533       new_offset = offset;
534       delta = 0;
535     }
536   result = _IO_SYSSEEK (fp, new_offset, 0);
537   if (result < 0)
538     return EOF;
539   if (delta == 0)
540     count = 0;
541   else
542     {
543       count = _IO_SYSREAD (fp, fp->_IO_buf_base,
544                            (must_be_exact
545                             ? delta : fp->_IO_buf_end - fp->_IO_buf_base));
546       if (count < delta)
547         {
548           /* We weren't allowed to read, but try to seek the remainder. */
549           offset = count == EOF ? delta : delta-count;
550           dir = _IO_seek_cur;
551           goto dumb;
552         }
553     }
554   _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base + delta,
555             fp->_IO_buf_base + count);
556   _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
557   fp->_offset = result + count;
558   _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
559   return offset;
560  dumb:
561
562   _IO_unsave_markers (fp);
563   result = _IO_SYSSEEK (fp, offset, dir);
564   if (result != EOF)
565     _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
566   fp->_offset = result;
567   _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
568   _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
569   return result;
570 }
571
572 _IO_ssize_t
573 _IO_file_read (fp, buf, size)
574      _IO_FILE *fp;
575      void *buf;
576      _IO_ssize_t size;
577 {
578   for (;;)
579     {
580       _IO_ssize_t count = _IO_read (fp->_fileno, buf, size);
581 #if 0 && defined EINTR
582       /* We must not do this optimization since POSIX.1 explicitly
583          requests that the stream operations must return with the
584          error EINTR if this happens.  There must be the possibility
585          that stream operations time out.  --drepper  */
586       if (count == -1 && errno == EINTR)
587         continue;
588 #endif
589       return count;
590     }
591 }
592
593 _IO_pos_t
594 _IO_file_seek (fp, offset, dir)
595      _IO_FILE *fp;
596      _IO_off_t offset;
597      int dir;
598 {
599   return _IO_lseek (fp->_fileno, offset, dir);
600 }
601
602 int
603 _IO_file_stat (fp, st)
604      _IO_FILE *fp;
605      void *st;
606 {
607   return _IO_fstat (fp->_fileno, (struct stat *) st);
608 }
609
610 int
611 _IO_file_close (fp)
612      _IO_FILE *fp;
613 {
614   return _IO_close (fp->_fileno);
615 }
616
617 _IO_ssize_t
618 _IO_file_write (f, data, n)
619      _IO_FILE *f;
620      const void *data;
621      _IO_ssize_t n;
622 {
623   _IO_ssize_t to_do = n;
624   while (to_do > 0)
625     {
626       _IO_ssize_t count = _IO_write (f->_fileno, data, to_do);
627       if (count == EOF)
628         {
629 #if 0 && defined EINTR
630           /* We must not do this optimization since POSIX.1 explicitly
631              requests that the stream operations must return with the
632              error EINTR if this happens.  There must be the
633              possibility that stream operations time out.  --drepper  */
634           if (errno == EINTR)
635             continue;
636           else
637 #endif
638             {
639               f->_flags |= _IO_ERR_SEEN;
640               break;
641             }
642         }
643       to_do -= count;
644       data = (void *) ((char *) data + count);
645     }
646   n -= to_do;
647   if (f->_offset >= 0)
648     f->_offset += n;
649   return n;
650 }
651
652 _IO_size_t
653 _IO_file_xsputn (f, data, n)
654      _IO_FILE *f;
655      const void *data;
656      _IO_size_t n;
657 {
658   register const char *s = (char *) data;
659   _IO_size_t to_do = n;
660   int must_flush = 0;
661   _IO_size_t count;
662
663   if (n <= 0)
664     return 0;
665   /* This is an optimized implementation.
666      If the amount to be written straddles a block boundary
667      (or the filebuf is unbuffered), use sys_write directly. */
668
669   /* First figure out how much space is available in the buffer. */
670   count = f->_IO_write_end - f->_IO_write_ptr; /* Space available. */
671   if ((f->_flags & _IO_LINE_BUF) && (f->_flags & _IO_CURRENTLY_PUTTING))
672     {
673       count = f->_IO_buf_end - f->_IO_write_ptr;
674       if (count >= n)
675         {
676           register const char *p;
677           for (p = s + n; p > s; )
678             {
679               if (*--p == '\n')
680                 {
681                   count = p - s + 1;
682                   must_flush = 1;
683                   break;
684                 }
685             }
686         }
687     }
688   /* Then fill the buffer. */
689   if (count > 0)
690     {
691       if (count > to_do)
692         count = to_do;
693       if (count > 20)
694         {
695           memcpy (f->_IO_write_ptr, s, count);
696           s += count;
697         }
698       else
699         {
700           register char *p = f->_IO_write_ptr;
701           register int i = (int) count;
702           while (--i >= 0)
703             *p++ = *s++;
704         }
705       f->_IO_write_ptr += count;
706       to_do -= count;
707     }
708   if (to_do + must_flush > 0)
709     {
710       _IO_size_t block_size, dont_write;
711       /* Next flush the (full) buffer. */
712       if (__overflow (f, EOF) == EOF)
713         return n - to_do;
714
715       /* Try to maintain alignment: write a whole number of blocks.
716          dont_write is what gets left over. */
717       block_size = f->_IO_buf_end - f->_IO_buf_base;
718       dont_write = block_size >= 128 ? to_do % block_size : 0;
719
720       count = to_do - dont_write;
721       if (_IO_do_write (f, s, count) == EOF)
722         return n - to_do;
723       to_do = dont_write;
724
725       /* Now write out the remainder.  Normally, this will fit in the
726          buffer, but it's somewhat messier for line-buffered files,
727          so we let _IO_default_xsputn handle the general case. */
728       if (dont_write)
729         to_do -= _IO_default_xsputn (f, s+count, dont_write);
730     }
731   return n - to_do;
732 }
733
734 #if 0
735 /* Work in progress */
736 _IO_size_t
737 _IO_file_xsgetn (fp, data, n)
738      _IO_FILE *fp;
739      void *data;
740      _IO_size_t n;
741 {
742   register _IO_size_t more = n;
743   register char *s = data;
744   for (;;)
745     {
746       /* Data available. */
747       _IO_ssize_t count = fp->_IO_read_end - fp->_IO_read_ptr;
748       if (count > 0)
749         {
750           if (count > more)
751             count = more;
752           if (count > 20)
753             {
754               memcpy (s, fp->_IO_read_ptr, count);
755               s += count;
756               fp->_IO_read_ptr += count;
757             }
758           else if (count <= 0)
759             count = 0;
760           else
761             {
762               register char *p = fp->_IO_read_ptr;
763               register int i = (int) count;
764               while (--i >= 0)
765                 *s++ = *p++;
766               fp->_IO_read_ptr = p;
767             }
768             more -= count;
769         }
770 #if 0
771       if (! _IO_in put_mode (fp)
772           && ! _IO_have_markers (fp) && ! IO_have_backup (fp))
773         {
774           /* This is an optimization of _IO_file_underflow */
775           if (fp->_flags & _IO_NO_READS)
776             break;
777           /* If we're reading a lot of data, don't bother allocating
778              a buffer.  But if we're only reading a bit, perhaps we should ??*/
779           if (count <= 512 && fp->_IO_buf_base == NULL)
780             _IO_doallocbuf (fp);
781           if (fp->_flags & (_IO_LINE_BUF|_IO_UNBUFFERED))
782             _IO_flush_all_linebuffered ();
783
784           _IO_switch_to_get_mode (fp); ???;
785           count = _IO_SYSREAD (fp, s, more);
786           if (count <= 0)
787              {
788                if (count == 0)
789                  fp->_flags |= _IO_EOF_SEEN;
790                else
791                  fp->_flags |= _IO_ERR_SEEN, count = 0;
792              }
793
794           s += count;
795           more -= count;
796         }
797 #endif
798       if (more == 0 || __underflow (fp) == EOF)
799         break;
800     }
801   return n - more;
802 }
803 #endif
804
805 struct _IO_jump_t _IO_file_jumps =
806 {
807   JUMP_INIT_DUMMY,
808   JUMP_INIT(finish, _IO_file_finish),
809   JUMP_INIT(overflow, _IO_file_overflow),
810   JUMP_INIT(underflow, _IO_file_underflow),
811   JUMP_INIT(uflow, _IO_default_uflow),
812   JUMP_INIT(pbackfail, _IO_default_pbackfail),
813   JUMP_INIT(xsputn, _IO_file_xsputn),
814   JUMP_INIT(xsgetn, _IO_default_xsgetn),
815   JUMP_INIT(seekoff, _IO_file_seekoff),
816   JUMP_INIT(seekpos, _IO_default_seekpos),
817   JUMP_INIT(setbuf, _IO_file_setbuf),
818   JUMP_INIT(sync, _IO_file_sync),
819   JUMP_INIT(doallocate, _IO_file_doallocate),
820   JUMP_INIT(read, _IO_file_read),
821   JUMP_INIT(write, _IO_file_write),
822   JUMP_INIT(seek, _IO_file_seek),
823   JUMP_INIT(close, _IO_file_close),
824   JUMP_INIT(stat, _IO_file_stat)
825 };