OSDN Git Service

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