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
36extern 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
103void
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
117int
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
144void
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
245int
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
279int
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
334int
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
385int
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
599int
600_IO_file_stat (fp, st)
601     _IO_FILE *fp;
602     void *st;
603{
604  return fstat (fp->_fileno, (struct stat *) st);
605}
606
607int
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
791struct _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};
812