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