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