OSDN Git Service

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