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